--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LXST/Filters.py 0.5.0 (9b9b186f) Text, 70.26 KB
T8b949e# Copyright 2024-2026, Mark Qvist
Tff7b72from T7ee787importlibT7ee787.T7ee787util Tff7b72import Te6edf3find_spec
Tff7b72from T7ee787collections Tff7b72import Te6edf3deque
Tff7b72import T7ee787numpy Tff7b72as T7ee787np
Tff7b72import T7ee787threading
Tff7b72import T7ee787time
Tff7b72import T7ee787RNS
Tff7b72import T7ee787os
Te6edf3USE_NATIVE_FILTERS Tff7b72= Tff7b72False
Tff7b72if Tff7b72not Te6edf3find_specTb4b4b4(Ta5d6ff"Ta5d6ffcffiTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not load CFFI module for filter acceleration, falling back to Python filters. This will be slow.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffMake sure that the CFFI module is installed and available.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787cffi Tff7b72import Te6edf3FFI
Tff7b72import T7ee787pathlib
Te6edf3c_src_path Tff7b72= Te6edf3pathlibTff7b72.Td2a8ffPathTb4b4b4(Tff7b72__file__Tb4b4b4)Tff7b72.Td2a8ffparentTff7b72.Td2a8ffresolveTb4b4b4(Tb4b4b4)
Te6edf3ffi Tff7b72= Te6edf3FFITb4b4b4(Tb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffvendorTff7b72.Td2a8ffplatformutilsTff7b72.Td2a8ffis_windowsTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3filterlib_spec Tff7b72= Te6edf3find_specTb4b4b4(Ta5d6ff"Ta5d6ffLXST.filterlibTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3filterlib_spec Tff7b72or Te6edf3filterlib_specTff7b72.Td2a8fforigin Tff7b72== Tff7b72NoneTb4b4b4: Tff7b72raise Tf85149ImportErrorTb4b4b4(Ta5d6ff"Ta5d6ffCould not locate pre-compiled LXST.filterlib moduleTa5d6ff"Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3c_src_pathTb4b4b4, Ta5d6ff"Ta5d6ffFilters.hTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffrTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4: Te6edf3ffiTff7b72.Td2a8ffcdefTb4b4b4(Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3native_functions Tff7b72= Te6edf3ffiTff7b72.Td2a8ffdlopenTb4b4b4(Te6edf3filterlib_specTff7b72.Td2a8fforiginTb4b4b4)
Te6edf3USE_NATIVE_FILTERS Tff7b72= Tff7b72True
Tff7b72elseTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3c_src_pathTb4b4b4, Ta5d6ff"Ta5d6ffFilters.hTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffrTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4: Te6edf3ffiTff7b72.Td2a8ffcdefTb4b4b4(Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3native_functions Tff7b72= Te6edf3ffiTff7b72.Td2a8ffdlopenTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3c_src_pathTb4b4b4, Ta5d6ff"Ta5d6fffilterlib.dllTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3USE_NATIVE_FILTERS Tff7b72= Tff7b72True
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not load pre-compiled LXST filters library. The contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffAttempting to compile library from source...Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72if Te6edf3USE_NATIVE_FILTERS Tff7b72== Tff7b72FalseTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3c_src_pathTb4b4b4, Ta5d6ff"Ta5d6ffFilters.hTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffrTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4: Te6edf3ffiTff7b72.Td2a8ffcdefTb4b4b4(Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3c_src_pathTb4b4b4, Ta5d6ff"Ta5d6ffFilters.cTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffrTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4: Te6edf3c_src Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Te6edf3native_functions Tff7b72= Te6edf3ffiTff7b72.Td2a8ffverifyTb4b4b4(Te6edf3c_srcTb4b4b4)
Te6edf3USE_NATIVE_FILTERS Tff7b72= Tff7b72True
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffSuccessfully compiled and loaded filters libraryTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffCould not compile modules for filter acceleration, falling back to Python filters. This will be slow.Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe contained exception was: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Te6edf3USE_NATIVE_FILTERS Tff7b72= Tff7b72False
Tff7b72class T56d364FilterTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4)Tb4b4b4:
Tff7b72raise Tf85149NotImplementedErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe handle_frame method was not implemented on Tffd700{Tff7b72selfTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72class T56d364HighPassTb4b4b4(Te6edf3FilterTb4b4b4)Tb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3cutTb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffcut Tff7b72= Te6edf3cut
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_last_inputs Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72= Tff7b72None
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
Tff7b72if Te6edf3samplerate Tff7b72!= Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Te6edf3samplerate
Te6edf3dt Tff7b72= T79c0ff1.0 Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_samplerate
Te6edf3rc Tff7b72= T79c0ff1.0 Tff7b72/ Tb4b4b4(T79c0ff2 Tff7b72* Te6edf3npTff7b72.Td2a8ffpi Tff7b72* Tff7b72selfTff7b72.Td2a8ffcutTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72= Te6edf3rc Tff7b72/ Tb4b4b4(Te6edf3rc Tff7b72+ Te6edf3dtTb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4) Tff7b72== T79c0ff1Tb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frameTff7b72.Td2a8ffreshapeTb4b4b4(Tff7b72-T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)
Tff7b72elseTb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frame
Te6edf3samplesTb4b4b4, Te6edf3channels Tff7b72= Te6edf3frame_2dTff7b72.Td2a8ffshape
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72is Tff7b72None Tff7b72or Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72!= Te6edf3channelsTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Te6edf3channels
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_channelsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_last_inputs Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_channelsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72if Te6edf3USE_NATIVE_FILTERSTb4b4b4:
Te6edf3frame_2d Tff7b72= Te6edf3npTff7b72.Td2a8ffascontiguousarrayTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3input_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3frame_2dTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3output_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3outputTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3states_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_filter_statesTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3last_inputs_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_last_inputsTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3native_functionsTff7b72.Td2a8ffhighpass_filterTb4b4b4(Te6edf3input_ptrTb4b4b4, Te6edf3output_ptrTb4b4b4, Te6edf3samplesTb4b4b4, Te6edf3channelsTb4b4b4, Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_alphaTb4b4b4)Tb4b4b4, Te6edf3states_ptrTb4b4b4, Te6edf3last_inputs_ptrTb4b4b4)
Te6edf3result Tff7b72= Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
Tff7b72return Te6edf3result
Tff7b72elseTb4b4b4:
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4)
Te6edf3input_diff_first Tff7b72= Te6edf3frame_2dTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72- Tff7b72selfTff7b72.Td2a8ff_last_inputs
Te6edf3outputTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72* Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72+ Te6edf3input_diff_firstTb4b4b4)
Te6edf3input_diff Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4)
Te6edf3input_diffTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= Te6edf3input_diff_first
Te6edf3input_diffTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4] Tff7b72= Te6edf3frame_2dTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4] Tff7b72- Te6edf3frame_2dTb4b4b4[Tb4b4b4:Tff7b72-T79c0ff1Tb4b4b4]
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3samplesTb4b4b4)Tb4b4b4:
Te6edf3outputTb4b4b4[Te6edf3iTb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72* Tb4b4b4(Te6edf3outputTb4b4b4[Te6edf3iTff7b72-T79c0ff1Tb4b4b4] Tff7b72+ Te6edf3input_diffTb4b4b4[Te6edf3iTb4b4b4]Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Te6edf3outputTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_last_inputs Tff7b72= Te6edf3frame_2dTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Te6edf3nframe Tff7b72= Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
Tff7b72return Te6edf3nframe
Tff7b72class T56d364LowPassTb4b4b4(Te6edf3FilterTb4b4b4)Tb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3cutTb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffcut Tff7b72= Te6edf3cut
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72= Tff7b72None
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
Tff7b72if Te6edf3samplerate Tff7b72!= Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Te6edf3samplerate
Te6edf3dt Tff7b72= T79c0ff1.0 Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_samplerate
Te6edf3rc Tff7b72= T79c0ff1.0 Tff7b72/ Tb4b4b4(T79c0ff2 Tff7b72* Te6edf3npTff7b72.Td2a8ffpi Tff7b72* Tff7b72selfTff7b72.Td2a8ffcutTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72= Te6edf3dt Tff7b72/ Tb4b4b4(Te6edf3rc Tff7b72+ Te6edf3dtTb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4) Tff7b72== T79c0ff1Tb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frameTff7b72.Td2a8ffreshapeTb4b4b4(Tff7b72-T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)
Tff7b72elseTb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frame
Te6edf3samplesTb4b4b4, Te6edf3channels Tff7b72= Te6edf3frame_2dTff7b72.Td2a8ffshape
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72is Tff7b72None Tff7b72or Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72!= Te6edf3channelsTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Te6edf3channels
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_channelsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72if Te6edf3USE_NATIVE_FILTERSTb4b4b4:
Te6edf3frame_2d Tff7b72= Te6edf3npTff7b72.Td2a8ffascontiguousarrayTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3input_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3frame_2dTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3output_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3outputTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3states_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_filter_statesTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3native_functionsTff7b72.Td2a8fflowpass_filterTb4b4b4(Te6edf3input_ptrTb4b4b4, Te6edf3output_ptrTb4b4b4, Te6edf3samplesTb4b4b4, Te6edf3channelsTb4b4b4, Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_alphaTb4b4b4)Tb4b4b4, Te6edf3states_ptrTb4b4b4)
Tff7b72return Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4)
Te6edf3outputTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72* Te6edf3frame_2dTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72+ Tb4b4b4(T79c0ff1.0 Tff7b72- Tff7b72selfTff7b72.Td2a8ff_alphaTb4b4b4) Tff7b72* Tff7b72selfTff7b72.Td2a8ff_filter_states
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3samplesTb4b4b4)Tb4b4b4:
Te6edf3outputTb4b4b4[Te6edf3iTb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_alpha Tff7b72* Te6edf3frame_2dTb4b4b4[Te6edf3iTb4b4b4] Tff7b72+ Tb4b4b4(T79c0ff1.0 Tff7b72- Tff7b72selfTff7b72.Td2a8ff_alphaTb4b4b4) Tff7b72* Te6edf3outputTb4b4b4[Te6edf3iTff7b72-T79c0ff1Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_filter_states Tff7b72= Te6edf3outputTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
Tff7b72class T56d364BandPassTb4b4b4(Te6edf3FilterTb4b4b4)Tb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3low_cutTb4b4b4, Te6edf3high_cutTb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3low_cut Tff7b72>Tff7b72= Te6edf3high_cutTb4b4b4: Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffLow-cut frequency must be less than high-cut frequencyTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fflow_cut Tff7b72= Te6edf3low_cut
Tff7b72selfTff7b72.Td2a8ffhigh_cut Tff7b72= Te6edf3high_cut
Tff7b72selfTff7b72.Td2a8ff_high_pass Tff7b72= Te6edf3HighPassTb4b4b4(Tff7b72selfTff7b72.Td2a8fflow_cutTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_low_pass Tff7b72= Te6edf3LowPassTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhigh_cutTb4b4b4)
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
T8b949e# TODO: Remove debug
Te6edf3st Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
Te6edf3high_passed Tff7b72= Tff7b72selfTff7b72.Td2a8ff_high_passTff7b72.Td2a8ffhandle_frameTb4b4b4(Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)
Te6edf3band_passed Tff7b72= Tff7b72selfTff7b72.Td2a8ff_low_passTff7b72.Td2a8ffhandle_frameTb4b4b4(Te6edf3high_passedTb4b4b4, Te6edf3samplerateTb4b4b4)
Te6edf3dt Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3st
Tff7b72if Te6edf3dt Tff7b72> T79c0ff0.010Tb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffSlow filter processing detected: Filter ran in Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyshorttimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3stTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72return Te6edf3band_passed
Tff7b72class T56d364AGCTb4b4b4(Te6edf3FilterTb4b4b4)Tb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3target_levelTff7b72=Tff7b72-T79c0ff12.0Tb4b4b4, Te6edf3max_gainTff7b72=T79c0ff12.0Tb4b4b4, Te6edf3attack_timeTff7b72=T79c0ff0.0001Tb4b4b4, Te6edf3release_timeTff7b72=T79c0ff0.002Tb4b4b4, Te6edf3hold_timeTff7b72=T79c0ff0.001Tb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fftrigger_level Tff7b72= T79c0ff0.003
Tff7b72selfTff7b72.Td2a8fftarget_level Tff7b72= Te6edf3target_level T8b949e# In dBFS
Tff7b72selfTff7b72.Td2a8ffmax_gain_db Tff7b72= Te6edf3max_gain
Tff7b72selfTff7b72.Td2a8ffattack_time Tff7b72= Te6edf3attack_time
Tff7b72selfTff7b72.Td2a8ffrelease_time Tff7b72= Te6edf3release_time
Tff7b72selfTff7b72.Td2a8ffhold_time Tff7b72= Te6edf3hold_time
Tff7b72selfTff7b72.Td2a8fftarget_linear Tff7b72= T79c0ff10 Tff7b72*Tff7b72* Tb4b4b4(Te6edf3target_level Tff7b72/ T79c0ff10Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffmax_gain_linear Tff7b72= T79c0ff10 Tff7b72*Tff7b72* Tb4b4b4(Te6edf3max_gain Tff7b72/ T79c0ff10Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_current_gain_lin Tff7b72= T79c0ff1.0
Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_block_target_s Tff7b72= T79c0ff0.01
Tff7b72selfTff7b72.Td2a8ff_attack_coeff Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_release_coeff Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_hold_samples Tff7b72= Tff7b72None
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
T8b949e# TODO: Remove debug
T8b949e# st = time.time()
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
Tff7b72if Tffa657lenTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4) Tff7b72== T79c0ff1Tb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frameTff7b72.Td2a8ffreshapeTb4b4b4(Tff7b72-T79c0ff1Tb4b4b4, T79c0ff1Tb4b4b4)
Tff7b72elseTb4b4b4: Te6edf3frame_2d Tff7b72= Te6edf3frame
Te6edf3samplesTb4b4b4, Te6edf3channels Tff7b72= Te6edf3frame_2dTff7b72.Td2a8ffshape
Tff7b72if Te6edf3samplerate Tff7b72!= Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Te6edf3samplerate
Tff7b72selfTff7b72.Td2a8ff_block_target Tff7b72= Tffa657intTb4b4b4(Tb4b4b4(Te6edf3samplesTff7b72/Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4)Tff7b72/Tff7b72selfTff7b72.Td2a8ff_block_target_sTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_calculate_coefficientsTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72is Tff7b72None Tff7b72or Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72!= Te6edf3channelsTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_channels Tff7b72= Te6edf3channels
Tff7b72selfTff7b72.Td2a8ff_current_gain_lin Tff7b72= Te6edf3npTff7b72.Td2a8ffonesTb4b4b4(Te6edf3channelsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72= T79c0ff0
Tff7b72if Te6edf3USE_NATIVE_FILTERSTb4b4b4:
Te6edf3frame_2d Tff7b72= Te6edf3npTff7b72.Td2a8ffascontiguousarrayTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3input_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3frame_2dTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3output_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Te6edf3outputTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3gain_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffcastTb4b4b4(Ta5d6ff"Ta5d6fffloat *Ta5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_current_gain_linTff7b72.Td2a8ffctypesTff7b72.Td2a8ffdataTb4b4b4)
Te6edf3hold_ptr Tff7b72= Te6edf3ffiTff7b72.Td2a8ffnewTb4b4b4(Ta5d6ff"Ta5d6ffint *Ta5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_hold_counterTb4b4b4)
Te6edf3native_functionsTff7b72.Td2a8ffagc_processTb4b4b4(
Te6edf3input_ptrTb4b4b4, Te6edf3output_ptrTb4b4b4, Te6edf3samplesTb4b4b4, Te6edf3channelsTb4b4b4,
Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8fftarget_linearTb4b4b4)Tb4b4b4, Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmax_gain_linearTb4b4b4)Tb4b4b4,
Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8fftrigger_levelTb4b4b4)Tb4b4b4,
Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_attack_coeffTb4b4b4)Tb4b4b4, Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_release_coeffTb4b4b4)Tb4b4b4,
Tffa657floatTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_hold_samplesTb4b4b4)Tb4b4b4,
Te6edf3gain_ptrTb4b4b4, Te6edf3hold_ptrTb4b4b4, Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_block_targetTb4b4b4)
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72= Te6edf3hold_ptrTb4b4b4[T79c0ff0Tb4b4b4]
Te6edf3result Tff7b72= Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
T8b949e# TODO: Remove debug
T8b949e# RNS.log(f"AGC ran in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_DEBUG)
Tff7b72return Te6edf3result
Tff7b72elseTb4b4b4:
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3frame_2dTb4b4b4)
Te6edf3block_size Tff7b72= Tffa657maxTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3samples Tff7b72/Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_block_targetTb4b4b4)
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3samplesTb4b4b4, Te6edf3block_sizeTb4b4b4)Tb4b4b4:
Te6edf3block_end Tff7b72= Tffa657minTb4b4b4(Te6edf3i Tff7b72+ Te6edf3block_sizeTb4b4b4, Te6edf3samplesTb4b4b4)
Te6edf3block Tff7b72= Te6edf3frame_2dTb4b4b4[Te6edf3iTb4b4b4:Te6edf3block_endTb4b4b4]
Te6edf3block_samples Tff7b72= Te6edf3block_end Tff7b72- Te6edf3i
Te6edf3rms Tff7b72= Te6edf3npTff7b72.Td2a8ffsqrtTb4b4b4(Te6edf3npTff7b72.Td2a8ffmeanTb4b4b4(Te6edf3block Tff7b72*Tff7b72* T79c0ff2Tb4b4b4, Te6edf3axisTff7b72=T79c0ff0Tb4b4b4)Tb4b4b4)
Te6edf3target_gain Tff7b72= Te6edf3npTff7b72.Td2a8ffwhereTb4b4b4(Te6edf3rms Tff7b72> T79c0ff1e-9Tb4b4b4, Tff7b72selfTff7b72.Td2a8fftarget_linear Tff7b72/ Te6edf3npTff7b72.Td2a8ffmaximumTb4b4b4(Te6edf3rmsTb4b4b4, T79c0ff1e-9Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ffmax_gain_linearTb4b4b4)
Te6edf3target_gain Tff7b72= Te6edf3npTff7b72.Td2a8ffminimumTb4b4b4(Te6edf3target_gainTb4b4b4, Tff7b72selfTff7b72.Td2a8ffmax_gain_linearTb4b4b4)
Te6edf3smoothed_gain Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3target_gainTb4b4b4)
Tff7b72for Te6edf3ch Tff7b72in Tffa657rangeTb4b4b4(Te6edf3channelsTb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(Te6edf3rmsTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72< Tff7b72selfTff7b72.Td2a8fftrigger_levelTb4b4b4)Tb4b4b4: Te6edf3target_gain Tff7b72= Tff7b72selfTff7b72.Td2a8ff_current_gain_lin
Tff7b72if Te6edf3target_gainTb4b4b4[Te6edf3chTb4b4b4] Tff7b72< Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4]Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_attack_coeff Tff7b72* Te6edf3target_gainTb4b4b4[Te6edf3chTb4b4b4] Tff7b72+ Tb4b4b4(T79c0ff1 Tff7b72- Tff7b72selfTff7b72.Td2a8ff_attack_coeffTb4b4b4) Tff7b72* Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72= Tff7b72selfTff7b72.Td2a8ff_hold_samples T8b949e# Reset hold counter
Tff7b72elseTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72> T79c0ff0Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_hold_counter Tff7b72-Tff7b72= Te6edf3block_samples
Tff7b72elseTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_release_coeff Tff7b72* Te6edf3target_gainTb4b4b4[Te6edf3chTb4b4b4] Tff7b72+ Tb4b4b4(T79c0ff1 Tff7b72- Tff7b72selfTff7b72.Td2a8ff_release_coeffTb4b4b4) Tff7b72* Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4]
Te6edf3smoothed_gainTb4b4b4[Te6edf3chTb4b4b4] Tff7b72= Tff7b72selfTff7b72.Td2a8ff_current_gain_linTb4b4b4[Te6edf3chTb4b4b4]
Te6edf3outputTb4b4b4[Te6edf3iTb4b4b4:Te6edf3block_endTb4b4b4] Tff7b72= Te6edf3block Tff7b72* Te6edf3smoothed_gainTb4b4b4[Te6edf3npTff7b72.Td2a8ffnewaxisTb4b4b4, Tb4b4b4:Tb4b4b4]
Te6edf3peak_limit Tff7b72= T79c0ff0.75
Te6edf3current_peaks Tff7b72= Te6edf3npTff7b72.Td2a8ffmaxTb4b4b4(Te6edf3npTff7b72.Td2a8ffabsTb4b4b4(Te6edf3outputTb4b4b4)Tb4b4b4, Te6edf3axisTff7b72=T79c0ff0Tb4b4b4)
Te6edf3limit_gain Tff7b72= Te6edf3npTff7b72.Td2a8ffwhereTb4b4b4(Te6edf3current_peaks Tff7b72> Te6edf3peak_limitTb4b4b4, Te6edf3peak_limit Tff7b72/ Te6edf3npTff7b72.Td2a8ffmaximumTb4b4b4(Te6edf3current_peaksTb4b4b4, T79c0ff1e-9Tb4b4b4)Tb4b4b4, T79c0ff1.0Tb4b4b4)
Tff7b72if Te6edf3npTff7b72.Td2a8ffanyTb4b4b4(Te6edf3limit_gain Tff7b72< T79c0ff1.0Tb4b4b4)Tb4b4b4: Te6edf3output Tff7b72*Tff7b72= Te6edf3limit_gainTb4b4b4[Te6edf3npTff7b72.Td2a8ffnewaxisTb4b4b4, Tb4b4b4:Tb4b4b4]
Te6edf3nframe Tff7b72= Te6edf3outputTff7b72.Td2a8ffreshapeTb4b4b4(Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4)
T8b949e# TODO: Remove debug
T8b949e# RNS.log(f"AGC ran in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_DEBUG)
Tff7b72return Te6edf3nframe
Tff7b72def Td2a8ff_calculate_coefficientsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_attack_coeff Tff7b72= T79c0ff1.0 Tff7b72- Te6edf3npTff7b72.Td2a8ffexpTb4b4b4(Tff7b72-T79c0ff1.0 Tff7b72/ Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffattack_time Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4)Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_release_coeff Tff7b72= T79c0ff1.0 Tff7b72- Te6edf3npTff7b72.Td2a8ffexpTb4b4b4(Tff7b72-T79c0ff1.0 Tff7b72/ Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffrelease_time Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4)Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_hold_samples Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhold_time Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerateTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_attack_coeff Tff7b72= T79c0ff0.1
Tff7b72selfTff7b72.Td2a8ff_release_coeff Tff7b72= T79c0ff0.01
Tff7b72selfTff7b72.Td2a8ff_hold_samples Tff7b72= T79c0ff1000
Tff7b72class T56d364EchoSuppressorTb4b4b4(Te6edf3FilterTb4b4b4)Tb4b4b4:
Te6edf3DEFAULT_MAX_DELAY_MS Tff7b72= T79c0ff550
Te6edf3DEFAULT_TRACK_WINDOW_MS Tff7b72= T79c0ff150
Te6edf3DEFAULT_CORRELATION_FRAME_MS Tff7b72= T79c0ff120
Te6edf3DEFAULT_CORRELATION_THRESHOLD Tff7b72= T79c0ff0.070
Te6edf3DEFAULT_RMS_THRESHOLD Tff7b72= T79c0ff0.002
Te6edf3DEFAULT_EMA_ALPHA Tff7b72= T79c0ff0.2
Te6edf3DEFAULT_PREEMPH_ALPHA Tff7b72= T79c0ff0.95
Te6edf3DEFAULT_ACC_FORGET Tff7b72= T79c0ff0.92
Te6edf3DEFAULT_COUPLING_WINDOW_S Tff7b72= T79c0ff5.0
Te6edf3DEFAULT_COUPLING_PERCENTILE Tff7b72= T79c0ff15
Te6edf3DEFAULT_COUPLING_THRESHOLD_DB Tff7b72= Tff7b72-T79c0ff30.0
Te6edf3DEFAULT_GATE_RATIO_DB Tff7b72= Tff7b72-T79c0ff3.0
Te6edf3DEFAULT_CORR_THRESHOLD Tff7b72= T79c0ff0.13
Te6edf3DEFAULT_DTD_ENERGY_DB Tff7b72= T79c0ff3.0
Te6edf3DEFAULT_HANGOVER_MS Tff7b72= T79c0ff150
Te6edf3DEFAULT_ATTACK_MS Tff7b72= T79c0ff5
Te6edf3DEFAULT_RELEASE_MS Tff7b72= T79c0ff80
Te6edf3DEFAULT_REF_RMS_THRESHOLD Tff7b72= T79c0ff0.0001
Te6edf3REQUIRED_COUPLING_HISTORY Tff7b72= T79c0ff4
Te6edf3DEFAULT_ESTIMATE_EVERY_N Tff7b72= T79c0ff2
Te6edf3DEFAULT_CNG_ENABLED Tff7b72= Tff7b72True
Te6edf3DEFAULT_CNG_GAIN Tff7b72= T79c0ff0.0015
Te6edf3DEFAULT_CNG_COLOR Tff7b72= T79c0ff0.98
Te6edf3DEFAULT_CNG_BLOCK_SIZE Tff7b72= T79c0ff16384
Te6edf3LOG_INTERVAL_LOCKED Tff7b72= T79c0ff0.25
Te6edf3LOG_INTERVAL_SEARCH Tff7b72= T79c0ff0.5
Te6edf3LOG_INTERVAL_GATE Tff7b72= T79c0ff0.25
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3max_delay_msTff7b72=Te6edf3DEFAULT_MAX_DELAY_MSTb4b4b4, Te6edf3track_window_msTff7b72=Te6edf3DEFAULT_TRACK_WINDOW_MSTb4b4b4,
Te6edf3correlation_frame_msTff7b72=Te6edf3DEFAULT_CORRELATION_FRAME_MSTb4b4b4, Te6edf3correlation_thresholdTff7b72=Te6edf3DEFAULT_CORRELATION_THRESHOLDTb4b4b4,
Te6edf3rms_thresholdTff7b72=Te6edf3DEFAULT_RMS_THRESHOLDTb4b4b4, Te6edf3ema_alphaTff7b72=Te6edf3DEFAULT_EMA_ALPHATb4b4b4, Te6edf3preemph_alphaTff7b72=Te6edf3DEFAULT_PREEMPH_ALPHATb4b4b4,
Te6edf3acc_forgetTff7b72=Te6edf3DEFAULT_ACC_FORGETTb4b4b4, Te6edf3coupling_window_sTff7b72=Te6edf3DEFAULT_COUPLING_WINDOW_STb4b4b4,
Te6edf3coupling_percentileTff7b72=Te6edf3DEFAULT_COUPLING_PERCENTILETb4b4b4, Te6edf3coupling_threshold_dbTff7b72=Te6edf3DEFAULT_COUPLING_THRESHOLD_DBTb4b4b4,
Te6edf3gate_ratio_dbTff7b72=Te6edf3DEFAULT_GATE_RATIO_DBTb4b4b4, Te6edf3corr_thresholdTff7b72=Te6edf3DEFAULT_CORR_THRESHOLDTb4b4b4, Te6edf3dtd_energy_dbTff7b72=Te6edf3DEFAULT_DTD_ENERGY_DBTb4b4b4,
Te6edf3hangover_msTff7b72=Te6edf3DEFAULT_HANGOVER_MSTb4b4b4, Te6edf3attack_msTff7b72=Te6edf3DEFAULT_ATTACK_MSTb4b4b4, Te6edf3release_msTff7b72=Te6edf3DEFAULT_RELEASE_MSTb4b4b4,
Te6edf3ref_rms_thresholdTff7b72=Te6edf3DEFAULT_REF_RMS_THRESHOLDTb4b4b4, Te6edf3estimate_every_nTff7b72=Te6edf3DEFAULT_ESTIMATE_EVERY_NTb4b4b4,
Te6edf3cng_enabledTff7b72=Te6edf3DEFAULT_CNG_ENABLEDTb4b4b4, Te6edf3cng_gainTff7b72=Te6edf3DEFAULT_CNG_GAINTb4b4b4, Te6edf3cng_colorTff7b72=Te6edf3DEFAULT_CNG_COLORTb4b4b4)Tb4b4b4:
Tffa657superTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ff__init__Tb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffmax_delay_ms Tff7b72= Te6edf3max_delay_ms
Tff7b72selfTff7b72.Td2a8fftrack_window_ms Tff7b72= Te6edf3track_window_ms
Tff7b72selfTff7b72.Td2a8ffcorrelation_frame_ms Tff7b72= Te6edf3correlation_frame_ms
Tff7b72selfTff7b72.Td2a8ffcorrelation_threshold Tff7b72= Te6edf3correlation_threshold
Tff7b72selfTff7b72.Td2a8ffrms_threshold Tff7b72= Te6edf3rms_threshold
Tff7b72selfTff7b72.Td2a8ffema_alpha Tff7b72= Te6edf3ema_alpha
Tff7b72selfTff7b72.Td2a8ffpreemph_alpha Tff7b72= Te6edf3preemph_alpha
Tff7b72selfTff7b72.Td2a8ffacc_forget Tff7b72= Te6edf3acc_forget
Tff7b72selfTff7b72.Td2a8ffestimate_every_n Tff7b72= Te6edf3estimate_every_n
Tff7b72selfTff7b72.Td2a8ffdebug_metrics Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ffcng_enabled Tff7b72= Te6edf3cng_enabled
Tff7b72selfTff7b72.Td2a8ffcng_gain Tff7b72= Te6edf3cng_gain
Tff7b72selfTff7b72.Td2a8ffcng_color Tff7b72= Tffa657minTb4b4b4(Tffa657maxTb4b4b4(Tffa657floatTb4b4b4(Te6edf3cng_colorTb4b4b4)Tb4b4b4, T79c0ff0.0Tb4b4b4)Tb4b4b4, T79c0ff0.999Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffcoupling_window_s Tff7b72= Te6edf3coupling_window_s
Tff7b72selfTff7b72.Td2a8ffcoupling_percentile Tff7b72= Te6edf3coupling_percentile
Tff7b72selfTff7b72.Td2a8ffcoupling_threshold_db Tff7b72= Te6edf3coupling_threshold_db
Tff7b72selfTff7b72.Td2a8ffgate_ratio_db Tff7b72= Te6edf3gate_ratio_db
Tff7b72selfTff7b72.Td2a8ffcorr_threshold Tff7b72= Te6edf3corr_threshold
Tff7b72selfTff7b72.Td2a8ffdtd_energy_db Tff7b72= Te6edf3dtd_energy_db
Tff7b72selfTff7b72.Td2a8ffhangover_ms Tff7b72= Te6edf3hangover_ms
Tff7b72selfTff7b72.Td2a8ffattack_ms Tff7b72= Te6edf3attack_ms
Tff7b72selfTff7b72.Td2a8ffrelease_ms Tff7b72= Te6edf3release_ms
Tff7b72selfTff7b72.Td2a8ffref_rms_threshold Tff7b72= Te6edf3ref_rms_threshold
Tff7b72selfTff7b72.Td2a8ff_last_echo_correlation Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_near_end_active_hold Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ffecho_correlation_window Tff7b72= T79c0ff1.0
Tff7b72selfTff7b72.Td2a8ffser_db Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_lock Tff7b72= Te6edf3threadingTff7b72.Td2a8ffLockTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Tff7b72None
T8b949e# 48 kHz buffers (gating path)
Tff7b72selfTff7b72.Td2a8ff_buffer_size Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_ref_buffer Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_ref_valid Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_max_delay_samples Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_track_window_samples Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_correlation_samples Tff7b72= Tff7b72None
T8b949e# Downsampling
T8b949e# self._decim_factor = 3
T8b949e# self._decim_taps = self._design_decimator_taps(num_taps=12, cutoff_hz=7500, samplerate=48000)
Tff7b72selfTff7b72.Td2a8ff_decim_factor Tff7b72= T79c0ff6
Tff7b72selfTff7b72.Td2a8ff_decim_taps Tff7b72= Tff7b72selfTff7b72.Td2a8ff_design_decimator_tapsTb4b4b4(Te6edf3num_tapsTff7b72=T79c0ff12Tb4b4b4, Te6edf3cutoff_hzTff7b72=T79c0ff3700Tb4b4b4, Te6edf3samplerateTff7b72=T79c0ff48000Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_decim_state_ref Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_decim_total_ref Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_decim_state_mic Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_decim_total_mic Tff7b72= T79c0ff0
T8b949e# Comfort noise generator
Tff7b72selfTff7b72.Td2a8ff_cng_buffer Tff7b72= Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_cng_buffer_pos Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_cng_state Tff7b72= T79c0ff0.0
Tff7b72selfTff7b72.Td2a8ff_cng_block_size Tff7b72= Tff7b72selfTff7b72.Td2a8ffDEFAULT_CNG_BLOCK_SIZE
T8b949e# 16 kHz buffers (delay-estimation path)
Tff7b72selfTff7b72.Td2a8ff_samplerate_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_ref_buffer_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_ref_valid_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_max_delay_samples_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_track_window_samples_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds Tff7b72= Tff7b72None
T8b949e# Pre-emphasis states
Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state_ds Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state_ds Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
T8b949e# Mic history (48 kHz unused, kept for API compat; 16 kHz active)
Tff7b72selfTff7b72.Td2a8ff_mic_hist Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_corr_acc Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_corr_acc_ds Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_delay_ms Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8ff_delay_confidence Tff7b72= T79c0ff0.0
Tff7b72selfTff7b72.Td2a8ff_last_log_time Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_last_gate_log_time Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_frame_count Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_coupling_history Tff7b72= Te6edf3dequeTb4b4b4(Te6edf3maxlenTff7b72=T79c0ff10Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_coupling Tff7b72= T79c0ff1e-3
Tff7b72selfTff7b72.Td2a8ff_coupling_db Tff7b72= Tff7b72-T79c0ff30.0
Tff7b72selfTff7b72.Td2a8ff_disabled_by_coupling Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72= T79c0ff1.0
Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_last_gate_open Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8ff_ser_db_threshold Tff7b72= T79c0ff11.0
Tff7b72selfTff7b72.Td2a8ff_ser_hysterisis Tff7b72= T79c0ff2
Tff7b72selfTff7b72.Td2a8ff_ser_threshold_count Tff7b72= T79c0ff0
T8b949e# Helpers
Tf0883e@staticmethod
Tff7b72def Td2a8ff_to_monoTb4b4b4(Te6edf3frameTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3frameTff7b72.Td2a8ffndim Tff7b72== T79c0ff1Tb4b4b4: Tff7b72return Te6edf3frameTff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4, Te6edf3copyTff7b72=Tff7b72FalseTb4b4b4)
Tff7b72elif Te6edf3frameTff7b72.Td2a8ffndim Tff7b72== T79c0ff2Tb4b4b4:
Tff7b72if Te6edf3frameTff7b72.Td2a8ffshapeTb4b4b4[T79c0ff1Tb4b4b4] Tff7b72== T79c0ff1Tb4b4b4: Tff7b72return Te6edf3frameTb4b4b4[Tb4b4b4:Tb4b4b4, T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4, Te6edf3copyTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3mono Tff7b72= Te6edf3frameTb4b4b4[Tb4b4b4:Tb4b4b4, T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Te6edf3mono Tff7b72+Tff7b72= Te6edf3frameTb4b4b4[Tb4b4b4:Tb4b4b4, T79c0ff1Tb4b4b4]
Te6edf3mono Tff7b72*Tff7b72= T79c0ff0.5
Tff7b72if Te6edf3monoTff7b72.Td2a8ffdtype Tff7b72!= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4: Tff7b72return Te6edf3monoTff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3mono
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3frameTff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4, Te6edf3copyTff7b72=Tff7b72FalseTb4b4b4)Tff7b72.Td2a8ffravelTb4b4b4(Tb4b4b4)
T8b949e# @staticmethod
T8b949e# def _to_mono(frame):
T8b949e# if frame.ndim == 1: return frame.astype(np.float32, copy=False)
T8b949e# elif frame.ndim == 2:
T8b949e# if frame.shape[1] == 1: return frame[:, 0].astype(np.float32, copy=False)
T8b949e# return frame.mean(axis=1).astype(np.float32)
T8b949e# else: return frame.astype(np.float32, copy=False).ravel()
Tf0883e@staticmethod
Tff7b72def Td2a8ff_design_decimator_tapsTb4b4b4(Te6edf3num_tapsTff7b72=T79c0ff12Tb4b4b4, Te6edf3cutoff_hzTff7b72=T79c0ff7500Tb4b4b4, Te6edf3samplerateTff7b72=T79c0ff48000Tb4b4b4)Tb4b4b4:
Te6edf3n Tff7b72= Te6edf3npTff7b72.Td2a8ffarangeTb4b4b4(Te6edf3num_tapsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat64Tb4b4b4)
Te6edf3fc Tff7b72= Te6edf3cutoff_hz Tff7b72/ Te6edf3samplerate
Te6edf3m Tff7b72= Te6edf3n Tff7b72- Tb4b4b4(Te6edf3num_taps Tff7b72- T79c0ff1Tb4b4b4) Tff7b72/ T79c0ff2.0
Te6edf3h Tff7b72= T79c0ff2.0 Tff7b72* Te6edf3fc Tff7b72* Te6edf3npTff7b72.Td2a8ffsincTb4b4b4(T79c0ff2.0 Tff7b72* Te6edf3fc Tff7b72* Te6edf3mTb4b4b4)
Te6edf3w Tff7b72= T79c0ff0.54 Tff7b72- T79c0ff0.46 Tff7b72* Te6edf3npTff7b72.Td2a8ffcosTb4b4b4(T79c0ff2.0 Tff7b72* Te6edf3npTff7b72.Td2a8ffpi Tff7b72* Te6edf3n Tff7b72/ Tb4b4b4(Te6edf3num_taps Tff7b72- T79c0ff1Tb4b4b4)Tb4b4b4)
Te6edf3h Tff7b72= Te6edf3h Tff7b72* Te6edf3w
Te6edf3h Tff7b72= Te6edf3h Tff7b72/ Te6edf3npTff7b72.Td2a8ffsumTb4b4b4(Te6edf3hTb4b4b4)
Tff7b72return Te6edf3hTff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72def Td2a8ff_decimateTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3xTb4b4b4, Te6edf3state_attrTb4b4b4, Te6edf3total_attrTb4b4b4)Tb4b4b4:
Te6edf3x Tff7b72= Te6edf3npTff7b72.Td2a8ffasarrayTb4b4b4(Te6edf3xTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3xTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4:
Tff7b72return Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3L Tff7b72= Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4)
Te6edf3state Tff7b72= Tffa657getattrTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3state_attrTb4b4b4)
Te6edf3total Tff7b72= Tffa657getattrTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3total_attrTb4b4b4)
Te6edf3buf Tff7b72= Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4(Tb4b4b4(Te6edf3stateTb4b4b4, Te6edf3xTb4b4b4)Tb4b4b4)
Te6edf3y Tff7b72= Te6edf3npTff7b72.Td2a8ffconvolveTb4b4b4(Te6edf3bufTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4, Te6edf3modeTff7b72=Ta5d6ff'Ta5d6ffvalidTa5d6ff'Tb4b4b4)
Te6edf3m Tff7b72= Tb4b4b4(Tff7b72-Te6edf3totalTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_decim_factor
Te6edf3out Tff7b72= Te6edf3yTb4b4b4[Te6edf3mTb4b4b4:Tb4b4b4:Tff7b72selfTff7b72.Td2a8ff_decim_factorTb4b4b4]
Tffa657setattrTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3total_attrTb4b4b4, Te6edf3total Tff7b72+ Tffa657lenTb4b4b4(Te6edf3xTb4b4b4)Tb4b4b4)
Tffa657setattrTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3state_attrTb4b4b4, Te6edf3bufTb4b4b4[Tff7b72-Tb4b4b4(Te6edf3L Tff7b72- T79c0ff1Tb4b4b4)Tb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72return Te6edf3out
Tff7b72def Td2a8ff_preemphTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3xTb4b4b4, Te6edf3stateTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3xTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3xTb4b4b4, Te6edf3state
Te6edf3y Tff7b72= Te6edf3npTff7b72.Td2a8ffempty_likeTb4b4b4(Te6edf3xTb4b4b4)
Te6edf3a Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffpreemph_alphaTb4b4b4)
Te6edf3yTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= Te6edf3xTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72- Te6edf3a Tff7b72* Te6edf3state
Te6edf3yTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4] Tff7b72= Te6edf3xTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4] Tff7b72- Te6edf3a Tff7b72* Te6edf3xTb4b4b4[Tb4b4b4:Tff7b72-T79c0ff1Tb4b4b4]
Tff7b72return Te6edf3yTb4b4b4, Te6edf3xTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]
Tff7b72def Td2a8ff_generate_cng_blockTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3nTb4b4b4)Tb4b4b4:
Te6edf3white Tff7b72= Te6edf3npTff7b72.Td2a8ffrandomTff7b72.Td2a8ffnormalTb4b4b4(T79c0ff0Tb4b4b4, T79c0ff1Tb4b4b4, Te6edf3nTb4b4b4)Tff7b72.Td2a8ffastypeTb4b4b4(Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3out Tff7b72= Te6edf3npTff7b72.Td2a8ffemptyTb4b4b4(Te6edf3nTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3s Tff7b72= Tff7b72selfTff7b72.Td2a8ff_cng_state
Te6edf3a Tff7b72= Tff7b72selfTff7b72.Td2a8ffcng_color
T8b949e# Normalise so output RMS ≈ cng_gain regardless of alpha
Te6edf3scale Tff7b72= Tff7b72selfTff7b72.Td2a8ffcng_gain Tff7b72* Te6edf3npTff7b72.Td2a8ffsqrtTb4b4b4(Tffa657maxTb4b4b4(T79c0ff0.0Tb4b4b4, T79c0ff1.0 Tff7b72- Te6edf3a Tff7b72* Te6edf3aTb4b4b4)Tb4b4b4)
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(Te6edf3nTb4b4b4)Tb4b4b4:
Te6edf3s Tff7b72= Te6edf3a Tff7b72* Te6edf3s Tff7b72+ Te6edf3whiteTb4b4b4[Te6edf3iTb4b4b4]
Te6edf3outTb4b4b4[Te6edf3iTb4b4b4] Tff7b72= Te6edf3s Tff7b72* Te6edf3scale
Tff7b72selfTff7b72.Td2a8ff_cng_state Tff7b72= Te6edf3s
Tff7b72return Te6edf3out
Tff7b72def Td2a8ff_get_cngTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3nTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_cng_buffer_pos Tff7b72+ Te6edf3n Tff7b72> Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_cng_bufferTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_cng_buffer Tff7b72= Tff7b72selfTff7b72.Td2a8ff_generate_cng_blockTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_cng_block_sizeTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_cng_buffer_pos Tff7b72= T79c0ff0
Te6edf3result Tff7b72= Tff7b72selfTff7b72.Td2a8ff_cng_bufferTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_cng_buffer_posTb4b4b4:Tff7b72selfTff7b72.Td2a8ff_cng_buffer_pos Tff7b72+ Te6edf3nTb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_cng_buffer_pos Tff7b72+Tff7b72= Te6edf3n
Tff7b72return Te6edf3result
T8b949e# Buffer management
Tff7b72def Td2a8ff_ensure_bufferTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72!= Te6edf3samplerate Tff7b72or Tff7b72selfTff7b72.Td2a8ff_ref_buffer Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72= Te6edf3samplerate
Tff7b72selfTff7b72.Td2a8ff_max_delay_samples Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmax_delay_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Te6edf3samplerateTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_track_window_samples Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8fftrack_window_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Te6edf3samplerateTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_correlation_samples Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffcorrelation_frame_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Te6edf3samplerateTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_buffer_size Tff7b72= Tff7b72selfTff7b72.Td2a8ff_max_delay_samples Tff7b72+ T79c0ff16384
Tff7b72selfTff7b72.Td2a8ff_ref_buffer Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_ref_valid Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_corr_acc Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_max_delay_samples Tff7b72+ T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat64Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_hist Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid Tff7b72= T79c0ff0
T8b949e# 16 kHz path
Tff7b72selfTff7b72.Td2a8ff_samplerate_ds Tff7b72= Tffa657intTb4b4b4(Te6edf3samplerate Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_decim_factorTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_max_delay_samples_ds Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmax_delay_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerate_dsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_track_window_samples_ds Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8fftrack_window_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerate_dsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffcorrelation_frame_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Tff7b72selfTff7b72.Td2a8ff_samplerate_dsTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_max_delay_samples_ds Tff7b72+ T79c0ff4096
Tff7b72selfTff7b72.Td2a8ff_ref_buffer_ds Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_ref_valid_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_corr_acc_ds Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_max_delay_samples_ds Tff7b72+ T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat64Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_hist_ds Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72= T79c0ff0
T8b949e# Reset decimator states
Tff7b72selfTff7b72.Td2a8ff_decim_state_ref Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_decim_total_ref Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_decim_state_mic Tff7b72= Te6edf3npTff7b72.Td2a8ffzerosTb4b4b4(Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_decim_tapsTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_decim_total_mic Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state_ds Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state_ds Tff7b72= Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4(T79c0ff0.0Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_coupling_historyTff7b72.Td2a8ffclearTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_coupling Tff7b72= T79c0ff1e-3
Tff7b72selfTff7b72.Td2a8ff_coupling_db Tff7b72= Tff7b72-T79c0ff30.0
Tff7b72selfTff7b72.Td2a8ff_disabled_by_coupling Tff7b72= Tff7b72False
Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72= T79c0ff1.0
Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_last_gate_open Tff7b72= Tff7b72True
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffEchoSuppressor initialised: max_delay=Tffd700{Tff7b72selfTff7b72.Td2a8ffmax_delay_msTffd700}Ta5d6ffms, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffcorr_window=Tffd700{Tff7b72selfTff7b72.Td2a8ffcorrelation_frame_msTffd700}Ta5d6ffms, threshold=Tffd700{Tff7b72selfTff7b72.Td2a8ffcorrelation_thresholdTffd700}Ta5d6ff, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffcoupling_th=Tffd700{Tff7b72selfTff7b72.Td2a8ffcoupling_threshold_dbTffd700}Ta5d6ffdB, gate_ratio=Tffd700{Tff7b72selfTff7b72.Td2a8ffgate_ratio_dbTffd700}Ta5d6ffdB, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffDTD=Tffd700{Tff7b72selfTff7b72.Td2a8ffdtd_energy_dbTffd700}Ta5d6ffdB, hangover=Tffd700{Tff7b72selfTff7b72.Td2a8ffhangover_msTffd700}Ta5d6ffms, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffattack=Tffd700{Tff7b72selfTff7b72.Td2a8ffattack_msTffd700}Ta5d6ffms, release=Tffd700{Tff7b72selfTff7b72.Td2a8ffrelease_msTffd700}Ta5d6ffms, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffest_rate=1/Tffd700{Tff7b72selfTff7b72.Td2a8ffestimate_every_nTffd700}Ta5d6ff, ds=Tffd700{Tff7b72selfTff7b72.Td2a8ff_samplerate_dsTffd700}Ta5d6ffHz, @ Tffd700{Te6edf3samplerateTffd700}Ta5d6ffHzTa5d6ff"Tb4b4b4,
Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72def Td2a8ff_append_referenceTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3monoTb4b4b4)Tb4b4b4:
Te6edf3N Tff7b72= Tffa657lenTb4b4b4(Te6edf3monoTb4b4b4)
Tff7b72if Te6edf3N Tff7b72> Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4:
Te6edf3mono Tff7b72= Te6edf3monoTb4b4b4[Tff7b72-Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4:Tb4b4b4]
Te6edf3N Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_size
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72+ Te6edf3N
Tff7b72if Te6edf3end Tff7b72<Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_ref_write_posTb4b4b4:Te6edf3endTb4b4b4] Tff7b72= Te6edf3mono
Tff7b72elseTb4b4b4:
Te6edf3part1 Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_size Tff7b72- Tff7b72selfTff7b72.Td2a8ff_ref_write_pos
Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_ref_write_posTb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tb4b4b4:Te6edf3part1Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Tb4b4b4:Te6edf3end Tff7b72- Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Te6edf3part1Tb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72= Te6edf3end Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size
Tff7b72selfTff7b72.Td2a8ff_ref_valid Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_valid Tff7b72+ Te6edf3NTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_buffer_sizeTb4b4b4)
Tff7b72def Td2a8ff_append_reference_dsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3monoTb4b4b4)Tb4b4b4:
Te6edf3N Tff7b72= Tffa657lenTb4b4b4(Te6edf3monoTb4b4b4)
Tff7b72if Te6edf3N Tff7b72> Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4:
Te6edf3mono Tff7b72= Te6edf3monoTb4b4b4[Tff7b72-Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4:Tb4b4b4]
Te6edf3N Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds Tff7b72+ Te6edf3N
Tff7b72if Te6edf3end Tff7b72<Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_dsTb4b4b4:Te6edf3endTb4b4b4] Tff7b72= Te6edf3mono
Tff7b72elseTb4b4b4:
Te6edf3part1 Tff7b72= Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds Tff7b72- Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds
Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_dsTb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tb4b4b4:Te6edf3part1Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Tb4b4b4:Te6edf3end Tff7b72- Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Te6edf3part1Tb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds Tff7b72= Te6edf3end Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds
Tff7b72selfTff7b72.Td2a8ff_ref_valid_ds Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_valid_ds Tff7b72+ Te6edf3NTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_buffer_size_dsTb4b4b4)
Tff7b72def Td2a8ff_append_mic_historyTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3monoTb4b4b4)Tb4b4b4:
Te6edf3N Tff7b72= Tffa657lenTb4b4b4(Te6edf3monoTb4b4b4)
Tff7b72if Te6edf3N Tff7b72>Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Tb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tff7b72-Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples
Tff7b72return
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72+ Te6edf3N
Tff7b72if Te6edf3end Tff7b72<Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_mic_hist_writeTb4b4b4:Te6edf3endTb4b4b4] Tff7b72= Te6edf3mono
Tff7b72elseTb4b4b4:
Te6edf3part1 Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples Tff7b72- Tff7b72selfTff7b72.Td2a8ff_mic_hist_write
Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_mic_hist_writeTb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tb4b4b4:Te6edf3part1Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Tb4b4b4:Te6edf3end Tff7b72- Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Te6edf3part1Tb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72= Te6edf3end Tff7b72% Tff7b72selfTff7b72.Td2a8ff_correlation_samples
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid Tff7b72+ Te6edf3NTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4)
Tff7b72def Td2a8ff_append_mic_history_dsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3monoTb4b4b4)Tb4b4b4:
Te6edf3N Tff7b72= Tffa657lenTb4b4b4(Te6edf3monoTb4b4b4)
Tff7b72if Te6edf3N Tff7b72>Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Tb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tff7b72-Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds
Tff7b72return
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72+ Te6edf3N
Tff7b72if Te6edf3end Tff7b72<Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_dsTb4b4b4:Te6edf3endTb4b4b4] Tff7b72= Te6edf3mono
Tff7b72elseTb4b4b4:
Te6edf3part1 Tff7b72= Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds Tff7b72- Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds
Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_dsTb4b4b4:Tb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Tb4b4b4:Te6edf3part1Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Tb4b4b4:Te6edf3end Tff7b72- Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4] Tff7b72= Te6edf3monoTb4b4b4[Te6edf3part1Tb4b4b4:Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72= Te6edf3end Tff7b72% Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds
Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72+ Te6edf3NTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4)
Tff7b72def Td2a8ff_get_reference_windowTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3lengthTb4b4b4)Tb4b4b4:
Te6edf3length Tff7b72= Tffa657minTb4b4b4(Te6edf3lengthTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_validTb4b4b4)
Tff7b72if Te6edf3length Tff7b72<Tff7b72= T79c0ff0Tb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3start Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72- Te6edf3lengthTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_ref_write_pos
Tff7b72if Te6edf3start Tff7b72< Te6edf3endTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4( Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Te6edf3startTb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Tb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4)
Tff7b72def Td2a8ff_get_reference_window_dsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3lengthTb4b4b4)Tb4b4b4:
Te6edf3length Tff7b72= Tffa657minTb4b4b4(Te6edf3lengthTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_valid_dsTb4b4b4)
Tff7b72if Te6edf3length Tff7b72<Tff7b72= T79c0ff0Tb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3start Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds Tff7b72- Te6edf3lengthTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size_ds
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_ref_write_pos_ds
Tff7b72if Te6edf3start Tff7b72< Te6edf3endTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4( Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Te6edf3startTb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_buffer_dsTb4b4b4[Tb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4)
Tff7b72def Td2a8ff_get_delayed_referenceTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3delay_samplesTb4b4b4, Te6edf3lengthTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3delay_samples Tff7b72+ Te6edf3length Tff7b72> Tff7b72selfTff7b72.Td2a8ff_ref_validTb4b4b4: Tff7b72return Tff7b72None
Te6edf3start Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72- Te6edf3delay_samples Tff7b72- Te6edf3lengthTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size
Te6edf3end Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_write_pos Tff7b72- Te6edf3delay_samplesTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_buffer_size
Tff7b72if Te6edf3start Tff7b72< Te6edf3endTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4( Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Te6edf3startTb4b4b4:Tb4b4b4]Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_bufferTb4b4b4[Tb4b4b4:Te6edf3endTb4b4b4]Tb4b4b4) Tb4b4b4)
Tff7b72def Td2a8ff_get_mic_historyTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3length Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_validTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_correlation_samplesTb4b4b4)
Tff7b72if Te6edf3length Tff7b72<Tff7b72= T79c0ff0Tb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3start Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_write Tff7b72- Te6edf3lengthTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_correlation_samples
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_mic_hist_write
Tff7b72if Te6edf3start Tff7b72< Te6edf3endTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4( Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Te6edf3startTb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_histTb4b4b4[Tb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4)
Tff7b72def Td2a8ff_get_mic_history_dsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3length Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_correlation_samples_dsTb4b4b4)
Tff7b72if Te6edf3length Tff7b72<Tff7b72= T79c0ff0Tb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat32Tb4b4b4)
Te6edf3start Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds Tff7b72- Te6edf3lengthTb4b4b4) Tff7b72% Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds
Te6edf3end Tff7b72= Tff7b72selfTff7b72.Td2a8ff_mic_hist_write_ds
Tff7b72if Te6edf3start Tff7b72< Te6edf3endTb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)
Tff7b72elseTb4b4b4: Tff7b72return Te6edf3npTff7b72.Td2a8ffconcatenateTb4b4b4( Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Te6edf3startTb4b4b4:Tb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_hist_dsTb4b4b4[Tb4b4b4:Te6edf3endTb4b4b4]Tff7b72.Td2a8ffcopyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4)
T8b949e# Coupling estimation
Tff7b72def Td2a8ff_update_couplingTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3mic_energyTb4b4b4, Te6edf3ref_energyTb4b4b4, Te6edf3corrTb4b4b4)Tb4b4b4:
Te6edf3mic_energy_threshold Tff7b72= T79c0ff6e-7
Te6edf3ref_energy_threshold Tff7b72= T79c0ff6e-7
Te6edf3in_bootstrap Tff7b72= Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_historyTb4b4b4) Tff7b72< Tff7b72selfTff7b72.Td2a8ffREQUIRED_COUPLING_HISTORY
Tff7b72if Tb4b4b4(Te6edf3ref_energy Tff7b72> Te6edf3ref_energy_threshold Tff7b72and Te6edf3corr Tff7b72> Tff7b72selfTff7b72.Td2a8ffcorr_threshold Tff7b72and Te6edf3mic_energy Tff7b72> Te6edf3mic_energy_thresholdTb4b4b4)Tb4b4b4:
Te6edf3ratio Tff7b72= Te6edf3mic_energy Tff7b72/ Te6edf3ref_energy
Tff7b72selfTff7b72.Td2a8ff_coupling_historyTff7b72.Td2a8ffappendTb4b4b4(Te6edf3ratioTb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_historyTb4b4b4) Tff7b72>Tff7b72= Tff7b72selfTff7b72.Td2a8ffREQUIRED_COUPLING_HISTORYTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_coupling Tff7b72= Te6edf3npTff7b72.Td2a8ffpercentileTb4b4b4(Te6edf3npTff7b72.Td2a8ffarrayTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_historyTb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat64Tb4b4b4)Tb4b4b4, Tff7b72selfTff7b72.Td2a8ffcoupling_percentileTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_coupling_db Tff7b72= T79c0ff10.0 Tff7b72* Te6edf3npTff7b72.Td2a8fflog10Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling Tff7b72+ T79c0ff1e-12Tb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_coupling_db Tff7b72< Tff7b72selfTff7b72.Td2a8ffcoupling_threshold_dbTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_disabled_by_coupling Tff7b72= Tff7b72True
Tff7b72elif Tff7b72selfTff7b72.Td2a8ff_coupling_db Tff7b72> Tff7b72selfTff7b72.Td2a8ffcoupling_threshold_db Tff7b72+ T79c0ff1.5Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_disabled_by_coupling Tff7b72= Tff7b72False
T8b949e# Public interface
Tff7b72def Td2a8ffhandle_referenceTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
T8b949e# st = time.time()
Te6edf3mono Tff7b72= Tff7b72selfTff7b72.Td2a8ff_to_monoTb4b4b4(Te6edf3frameTb4b4b4)
T8b949e# RNS.log(f"Ref mono (dtype={frame.dtype}, ndim={frame.ndim}, frame.shape[1]={frame.shape[1]}) conversion in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_DEBUG)
T8b949e# 16 kHz path: downsample raw, then pre-emphasise
Te6edf3mono_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_decimateTb4b4b4(Te6edf3monoTb4b4b4, Ta5d6ff'Ta5d6ff_decim_state_refTa5d6ff'Tb4b4b4, Ta5d6ff'Ta5d6ff_decim_total_refTa5d6ff'Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3mono_dsTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3mono_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_preemphTb4b4b4(Te6edf3mono_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state_dsTb4b4b4)
T8b949e# 48 kHz path: pre-emphasise
Te6edf3monoTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_preemph_state Tff7b72= Tff7b72selfTff7b72.Td2a8ff_preemphTb4b4b4(Te6edf3monoTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_ref_preemph_stateTb4b4b4)
Tff7b72with Tff7b72selfTff7b72.Td2a8ff_lockTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_ensure_bufferTb4b4b4(Te6edf3samplerateTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_append_referenceTb4b4b4(Te6edf3monoTb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3mono_dsTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_append_reference_dsTb4b4b4(Te6edf3mono_dsTb4b4b4)
Tff7b72def Td2a8ffhandle_frameTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3frameTb4b4b4, Te6edf3samplerateTb4b4b4)Tb4b4b4:
Te6edf3st Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3original_shape Tff7b72= Te6edf3frameTff7b72.Td2a8ffshape
Te6edf3mono_raw Tff7b72= Tff7b72selfTff7b72.Td2a8ff_to_monoTb4b4b4(Te6edf3frameTb4b4b4)
Te6edf3N Tff7b72= Tffa657lenTb4b4b4(Te6edf3mono_rawTb4b4b4)
Tff7b72if Te6edf3N Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
T8b949e# mic_rms = np.sqrt(np.mean(mono_raw ** 2)) # TODO: Remove and clean
T8b949e# if mic_rms < self.rms_threshold: return frame
T8b949e# RNS.log(f"Mono conversion (dtype={frame.dtype}, ndim={frame.ndim}, frame.shape[1]={frame.shape[1]}) in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_DEBUG)
T8b949e# dst = time.time()
T8b949e# Downsample for delay estimation
Te6edf3mono_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_decimateTb4b4b4(Te6edf3mono_rawTb4b4b4, Ta5d6ff'Ta5d6ff_decim_state_micTa5d6ff'Tb4b4b4, Ta5d6ff'Ta5d6ff_decim_total_micTa5d6ff'Tb4b4b4)
T8b949e# RNS.log(f"Decimation in {RNS.prettyshorttime(time.time()-dst)}", RNS.LOG_DEBUG)
T8b949e# pest = time.time()
T8b949e# Pre-emphasis
Te6edf3mono_preTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state Tff7b72= Tff7b72selfTff7b72.Td2a8ff_preemphTb4b4b4(Te6edf3mono_rawTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_preemph_stateTb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3mono_dsTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4: Te6edf3mono_pre_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state_ds Tff7b72= Tff7b72selfTff7b72.Td2a8ff_preemphTb4b4b4(Te6edf3mono_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_mic_preemph_state_dsTb4b4b4)
Tff7b72elseTb4b4b4: Te6edf3mono_pre_ds Tff7b72= Te6edf3mono_ds
T8b949e# RNS.log(f"Pre-emphasis in {RNS.prettyshorttime(time.time()-pest)}", RNS.LOG_DEBUG)
T8b949e# 1. Delay estimation
Tff7b72selfTff7b72.Td2a8ff_frame_count Tff7b72+Tff7b72= T79c0ff1
Te6edf3ref_delayed Tff7b72= Tff7b72None
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_ref_valid Tff7b72< Te6edf3N Tff7b72+ T79c0ff100Tb4b4b4: Tff7b72return Te6edf3frame
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72!= Te6edf3samplerateTb4b4b4:
Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffEchoSuppressor samplerate mismatch (ref=Tffd700{Tff7b72selfTff7b72.Td2a8ff_samplerateTffd700}Ta5d6ff, mic=Tffd700{Te6edf3samplerateTffd700}Ta5d6ff), skippingTa5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_WARNINGTb4b4b4)
Tff7b72return Te6edf3frame
Tff7b72if Tff7b72not Tb4b4b4(Tff7b72selfTff7b72.Td2a8ff_frame_count Tff7b72% Tff7b72selfTff7b72.Td2a8ffestimate_every_nTb4b4b4) Tff7b72== T79c0ff0Tb4b4b4:
Tff7b72with Tff7b72selfTff7b72.Td2a8ff_lockTb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3mono_pre_dsTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_append_mic_history_dsTb4b4b4(Te6edf3mono_pre_dsTb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72< Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds Tff7b72/Tff7b72/ T79c0ff2Tb4b4b4: Tff7b72return Te6edf3frame
Tff7b72elseTb4b4b4:
T8b949e# pst = time.time()
Tff7b72with Tff7b72selfTff7b72.Td2a8ff_lockTb4b4b4:
Tff7b72if Tffa657lenTb4b4b4(Te6edf3mono_pre_dsTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_append_mic_history_dsTb4b4b4(Te6edf3mono_pre_dsTb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_mic_hist_valid_ds Tff7b72< Tff7b72selfTff7b72.Td2a8ff_correlation_samples_ds Tff7b72/Tff7b72/ T79c0ff2Tb4b4b4: Tff7b72return Te6edf3frame
Te6edf3mic_window Tff7b72= Tff7b72selfTff7b72.Td2a8ff_get_mic_history_dsTb4b4b4(Tb4b4b4)
Te6edf3search_length Tff7b72= Tffa657minTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_ref_valid_dsTb4b4b4, Tff7b72selfTff7b72.Td2a8ff_max_delay_samples_ds Tff7b72+ Tffa657lenTb4b4b4(Te6edf3mic_windowTb4b4b4)Tb4b4b4)
Tff7b72if Te6edf3search_length Tff7b72<Tff7b72= Tffa657lenTb4b4b4(Te6edf3mic_windowTb4b4b4)Tb4b4b4: Tff7b72return Te6edf3frame
Te6edf3ref_window Tff7b72= Tff7b72selfTff7b72.Td2a8ff_get_reference_window_dsTb4b4b4(Te6edf3search_lengthTb4b4b4)
T8b949e# RNS.log(f"Prep in {RNS.prettyshorttime(time.time()-pst)}", RNS.LOG_DEBUG)
T8b949e# fst = time.time()
T8b949e# FFT-based cross-correlation at 16 kHz
Te6edf3M Tff7b72= Tffa657lenTb4b4b4(Te6edf3ref_windowTb4b4b4)
Te6edf3Nc Tff7b72= Tffa657lenTb4b4b4(Te6edf3mic_windowTb4b4b4)
Te6edf3fft_size Tff7b72= T79c0ff1 Tff7b72<< Tb4b4b4(Te6edf3M Tff7b72+ Te6edf3Nc Tff7b72- T79c0ff1Tb4b4b4)Tff7b72.Td2a8ffbit_lengthTb4b4b4(Tb4b4b4)
Te6edf3C Tff7b72= Te6edf3npTff7b72.Td2a8fffftTff7b72.Td2a8ffirfftTb4b4b4( Te6edf3npTff7b72.Td2a8fffftTff7b72.Td2a8ffrfftTb4b4b4(Te6edf3ref_windowTb4b4b4, Te6edf3nTff7b72=Te6edf3fft_sizeTb4b4b4) Tff7b72*
Te6edf3npTff7b72.Td2a8ffconjTb4b4b4(Te6edf3npTff7b72.Td2a8fffftTff7b72.Td2a8ffrfftTb4b4b4(Te6edf3mic_windowTb4b4b4, Te6edf3nTff7b72=Te6edf3fft_sizeTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3nTff7b72=Te6edf3fft_size Tb4b4b4)
Te6edf3c Tff7b72= Te6edf3CTb4b4b4[Tb4b4b4:Te6edf3M Tff7b72- Te6edf3Nc Tff7b72+ T79c0ff1Tb4b4b4]
T8b949e# RNS.log(f"{fft_size} FFT ops in {RNS.prettyshorttime(time.time()-fst)}", RNS.LOG_DEBUG)
T8b949e# nst = time.time()
Te6edf3mic_norm Tff7b72= Te6edf3npTff7b72.Td2a8fflinalgTff7b72.Td2a8ffnormTb4b4b4(Te6edf3mic_windowTb4b4b4)
Tff7b72if Te6edf3mic_norm Tff7b72== T79c0ff0Tb4b4b4: Tff7b72return Te6edf3frame
Te6edf3ref_cumsum Tff7b72= Te6edf3npTff7b72.Td2a8ffemptyTb4b4b4(Tffa657lenTb4b4b4(Te6edf3ref_windowTb4b4b4) Tff7b72+ T79c0ff1Tb4b4b4, Te6edf3dtypeTff7b72=Te6edf3npTff7b72.Td2a8fffloat64Tb4b4b4)
Te6edf3ref_cumsumTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72= T79c0ff0.0
Te6edf3npTff7b72.Td2a8ffmultiplyTb4b4b4(Te6edf3ref_windowTb4b4b4, Te6edf3ref_windowTb4b4b4, Te6edf3outTff7b72=Te6edf3ref_cumsumTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4]Tb4b4b4)
Te6edf3npTff7b72.Td2a8ffcumsumTb4b4b4(Te6edf3ref_cumsumTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4]Tb4b4b4, Te6edf3outTff7b72=Te6edf3ref_cumsumTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4]Tb4b4b4)
Te6edf3window_norms Tff7b72= Te6edf3npTff7b72.Td2a8ffsqrtTb4b4b4(Te6edf3ref_cumsumTb4b4b4[Te6edf3NcTb4b4b4:Tb4b4b4] Tff7b72- Te6edf3ref_cumsumTb4b4b4[Tb4b4b4:Tff7b72-Te6edf3NcTb4b4b4]Tb4b4b4)
Tff7b72with Te6edf3npTff7b72.Td2a8fferrstateTb4b4b4(Te6edf3divideTff7b72=Ta5d6ff'Ta5d6ffignoreTa5d6ff'Tb4b4b4, Te6edf3invalidTff7b72=Ta5d6ff'Ta5d6ffignoreTa5d6ff'Tb4b4b4)Tb4b4b4: Te6edf3corr Tff7b72= Te6edf3c Tff7b72/ Tb4b4b4(Te6edf3mic_norm Tff7b72* Te6edf3window_normsTb4b4b4)
Te6edf3corrTb4b4b4[Te6edf3window_norms Tff7b72== T79c0ff0Tb4b4b4] Tff7b72= T79c0ff0
Te6edf3abs_corr Tff7b72= Te6edf3npTff7b72.Td2a8ffabsTb4b4b4(Te6edf3corrTb4b4b4)
T8b949e# RNS.log(f"Correlation in {RNS.prettyshorttime(time.time()-nst)}", RNS.LOG_DEBUG)
T8b949e# ast = time.time()
T8b949e# Accumulate
Tff7b72selfTff7b72.Td2a8ff_corr_acc_ds Tff7b72*Tff7b72= Tff7b72selfTff7b72.Td2a8ffacc_forget
Tff7b72selfTff7b72.Td2a8ff_corr_acc_dsTb4b4b4[Tb4b4b4:Tffa657lenTb4b4b4(Te6edf3abs_corrTb4b4b4)Tb4b4b4] Tff7b72+Tff7b72= Te6edf3abs_corrTb4b4b4[Tb4b4b4:Tb4b4b4:Tff7b72-T79c0ff1Tb4b4b4]
Te6edf3acc_norm Tff7b72= Tff7b72selfTff7b72.Td2a8ff_corr_acc_ds Tff7b72* Tb4b4b4(T79c0ff1.0 Tff7b72- Tff7b72selfTff7b72.Td2a8ffacc_forgetTb4b4b4)
Te6edf3abs_mean Tff7b72= Tffa657floatTb4b4b4(Te6edf3npTff7b72.Td2a8ffmeanTb4b4b4(Te6edf3abs_corrTb4b4b4)Tb4b4b4)
Te6edf3abs_std Tff7b72= Tffa657floatTb4b4b4(Te6edf3npTff7b72.Td2a8ffstdTb4b4b4(Te6edf3abs_corrTb4b4b4)Tb4b4b4)
T8b949e# RNS.log(f"Accumulation in {RNS.prettyshorttime(time.time()-ast)}", RNS.LOG_DEBUG)
T8b949e# pst = time.time()
T8b949e# Search for peak
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
T8b949e# _delay_samples is stored in 48 kHz units; convert to 16 kHz for search window
Te6edf3d_est_ds Tff7b72= Tffa657intTb4b4b4(Tffa657roundTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_decim_factorTb4b4b4)Tb4b4b4)
Te6edf3d_min Tff7b72= Tffa657maxTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3d_est_ds Tff7b72- Tff7b72selfTff7b72.Td2a8ff_track_window_samples_dsTb4b4b4)
Te6edf3d_max Tff7b72= Tffa657minTb4b4b4(Tffa657lenTb4b4b4(Te6edf3acc_normTb4b4b4) Tff7b72- T79c0ff1Tb4b4b4, Te6edf3d_est_ds Tff7b72+ Tff7b72selfTff7b72.Td2a8ff_track_window_samples_dsTb4b4b4)
Te6edf3track_acc Tff7b72= Te6edf3acc_normTb4b4b4[Te6edf3d_minTb4b4b4:Te6edf3d_max Tff7b72+ T79c0ff1Tb4b4b4]
Te6edf3best_local_idx Tff7b72= Te6edf3npTff7b72.Td2a8ffargmaxTb4b4b4(Te6edf3track_accTb4b4b4)
Te6edf3best_delay_ds Tff7b72= Te6edf3d_min Tff7b72+ Te6edf3best_local_idx
Te6edf3best_val Tff7b72= Tffa657floatTb4b4b4(Te6edf3track_accTb4b4b4[Te6edf3best_local_idxTb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3best_val Tff7b72< Tff7b72selfTff7b72.Td2a8ffcorrelation_thresholdTb4b4b4:
Te6edf3best_delay_ds Tff7b72= Tffa657intTb4b4b4(Te6edf3npTff7b72.Td2a8ffargmaxTb4b4b4(Te6edf3acc_normTb4b4b4)Tb4b4b4)
Te6edf3best_val Tff7b72= Tffa657floatTb4b4b4(Te6edf3acc_normTb4b4b4[Te6edf3best_delay_dsTb4b4b4]Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3best_delay_ds Tff7b72= Tffa657intTb4b4b4(Te6edf3npTff7b72.Td2a8ffargmaxTb4b4b4(Te6edf3acc_normTb4b4b4)Tb4b4b4)
Te6edf3best_val Tff7b72= Tffa657floatTb4b4b4(Te6edf3acc_normTb4b4b4[Te6edf3best_delay_dsTb4b4b4]Tb4b4b4)
Te6edf3prominence Tff7b72= Tb4b4b4(Te6edf3best_val Tff7b72- Te6edf3abs_meanTb4b4b4) Tff7b72/ Tb4b4b4(Te6edf3abs_std Tff7b72+ T79c0ff1e-12Tb4b4b4)
Te6edf3raw_delay_ms Tff7b72= Te6edf3best_delay_ds Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_samplerate_ds Tff7b72* T79c0ff1000.0
T8b949e# RNS.log(f"Peak search in {RNS.prettyshorttime(time.time()-pst)}", RNS.LOG_DEBUG)
T8b949e# rst = time.time()
Tff7b72if Te6edf3best_val Tff7b72>Tff7b72= Tff7b72selfTff7b72.Td2a8ffcorrelation_thresholdTb4b4b4:
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72= Tffa657floatTb4b4b4(Te6edf3best_delay_ds Tff7b72* Tff7b72selfTff7b72.Td2a8ff_decim_factorTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_delay_ms Tff7b72= Te6edf3raw_delay_ms
Tff7b72selfTff7b72.Td2a8ff_delay_confidence Tff7b72= Te6edf3best_val
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffema_alpha Tff7b72* Te6edf3best_delay_ds Tff7b72* Tff7b72selfTff7b72.Td2a8ff_decim_factor Tff7b72+
Tb4b4b4(T79c0ff1.0 Tff7b72- Tff7b72selfTff7b72.Td2a8ffema_alphaTb4b4b4) Tff7b72* Tff7b72selfTff7b72.Td2a8ff_delay_samplesTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_delay_ms Tff7b72= Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72/ Tff7b72selfTff7b72.Td2a8ff_samplerate Tff7b72* T79c0ff1000.0
Tff7b72selfTff7b72.Td2a8ff_delay_confidence Tff7b72= Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffema_alpha Tff7b72* Te6edf3best_val Tff7b72+
Tb4b4b4(T79c0ff1.0 Tff7b72- Tff7b72selfTff7b72.Td2a8ffema_alphaTb4b4b4) Tff7b72* Tff7b72selfTff7b72.Td2a8ff_delay_confidenceTb4b4b4)
T8b949e# RNS.log(f"Result calc in {RNS.prettyshorttime(time.time()-rst)}", RNS.LOG_DEBUG)
T8b949e# Fetch delayed reference aligned with current mic frame (48 kHz)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_delay_samples Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3int_delay Tff7b72= Tffa657intTb4b4b4(Tffa657roundTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_delay_samplesTb4b4b4)Tb4b4b4)
Te6edf3ref_delayed Tff7b72= Tff7b72selfTff7b72.Td2a8ff_get_delayed_referenceTb4b4b4(Te6edf3int_delayTb4b4b4, Te6edf3NTb4b4b4)
T8b949e# RNS.log(f"Total delay estimation in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_DEBUG) # TODO: Remove
T8b949e# 2. Echo detection and gating
Tff7b72if Te6edf3ref_delayed Tff7b72is Tff7b72None Tff7b72or Tffa657lenTb4b4b4(Te6edf3ref_delayedTb4b4b4) Tff7b72!= Te6edf3NTb4b4b4: Tff7b72return Te6edf3frame
T8b949e# Energy on pre-emphasised signals
Te6edf3mic_energy Tff7b72= Te6edf3npTff7b72.Td2a8ffmeanTb4b4b4(Te6edf3mono_pre Tff7b72*Tff7b72* T79c0ff2Tb4b4b4)
Te6edf3ref_energy Tff7b72= Te6edf3npTff7b72.Td2a8ffmeanTb4b4b4(Te6edf3ref_delayed Tff7b72*Tff7b72* T79c0ff2Tb4b4b4)
T8b949e# Normalised correlation
Te6edf3mic_norm Tff7b72= Te6edf3npTff7b72.Td2a8fflinalgTff7b72.Td2a8ffnormTb4b4b4(Te6edf3mono_preTb4b4b4)
Te6edf3ref_norm Tff7b72= Te6edf3npTff7b72.Td2a8fflinalgTff7b72.Td2a8ffnormTb4b4b4(Te6edf3ref_delayedTb4b4b4)
Tff7b72if Te6edf3mic_norm Tff7b72> T79c0ff1e-12 Tff7b72and Te6edf3ref_norm Tff7b72> T79c0ff1e-12Tb4b4b4: Te6edf3corr Tff7b72= Tffa657absTb4b4b4(Te6edf3npTff7b72.Td2a8ffdotTb4b4b4(Te6edf3mono_preTb4b4b4, Te6edf3ref_delayedTb4b4b4) Tff7b72/ Tb4b4b4(Te6edf3mic_norm Tff7b72* Te6edf3ref_normTb4b4b4)Tb4b4b4)
Tff7b72elseTb4b4b4: Te6edf3corr Tff7b72= T79c0ff0.0
T8b949e# Predicted echo energy from current coupling estimate
Te6edf3now Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3predicted_echo_energy Tff7b72= Tff7b72selfTff7b72.Td2a8ff_coupling Tff7b72* Te6edf3ref_energy
Tff7b72if Te6edf3corr Tff7b72> Tff7b72selfTff7b72.Td2a8ffcorr_thresholdTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_last_echo_correlation Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)
Te6edf3echo_correlated Tff7b72= Te6edf3now Tff7b72< Tff7b72selfTff7b72.Td2a8ff_last_echo_correlation Tff7b72+ Tff7b72selfTff7b72.Td2a8ffecho_correlation_window
Tff7b72if Te6edf3mic_energy Tff7b72> T79c0ff2e-6Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffser_db Tff7b72= T79c0ff10.0 Tff7b72* Te6edf3npTff7b72.Td2a8fflog10Tb4b4b4(Te6edf3mic_energyTff7b72/Te6edf3predicted_echo_energy Tff7b72+ T79c0ff1e-12Tb4b4b4)
T8b949e# Near-end energy estimate (residual after predicted echo)
Te6edf3near_energy Tff7b72= Tffa657maxTb4b4b4(T79c0ff0.0Tb4b4b4, Te6edf3mic_energy Tff7b72- Te6edf3predicted_echo_energyTb4b4b4)
T8b949e# Determine near-end activity
Te6edf3near_end_active Tff7b72= Tff7b72False
Te6edf3in_bootstrap Tff7b72= Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_historyTb4b4b4) Tff7b72< Tff7b72selfTff7b72.Td2a8ffREQUIRED_COUPLING_HISTORY
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_near_end_active_hold Tff7b72> Te6edf3nowTb4b4b4: Te6edf3near_end_active Tff7b72= Tff7b72True
Tff7b72elif Te6edf3in_bootstrapTb4b4b4: Te6edf3near_end_active Tff7b72= Te6edf3near_energy Tff7b72> T79c0ff2e-6 Tff7b72and Te6edf3corr Tff7b72< Tff7b72selfTff7b72.Td2a8ffcorr_threshold
Tff7b72elseTb4b4b4:
Tff7b72if Te6edf3now Tff7b72> Tff7b72selfTff7b72.Td2a8ff_last_echo_correlation Tff7b72+ Tff7b72selfTff7b72.Td2a8ffecho_correlation_windowTb4b4b4: Te6edf3near_end_active Tff7b72= Tff7b72True
Tff7b72if Tff7b72selfTff7b72.Td2a8ffser_db Tff7b72> Tff7b72selfTff7b72.Td2a8ff_ser_db_thresholdTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_ser_threshold_count Tff7b72+Tff7b72= T79c0ff1
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_ser_threshold_count Tff7b72>Tff7b72= Tff7b72selfTff7b72.Td2a8ff_ser_hysterisisTb4b4b4:
Te6edf3near_end_active Tff7b72= Tff7b72True
Tff7b72selfTff7b72.Td2a8ff_near_end_active_hold Tff7b72= Te6edf3nowTff7b72+T79c0ff0.75
Tff7b72elseTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_ser_threshold_count Tff7b72= T79c0ff0
T8b949e# Update coupling estimate
Tff7b72if Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Tff7b72selfTff7b72.Td2a8ff_last_echo_correlation Tff7b72+ Tff7b72selfTff7b72.Td2a8ffecho_correlation_windowTb4b4b4: Tff7b72selfTff7b72.Td2a8ff_update_couplingTb4b4b4(Te6edf3mic_energyTb4b4b4, Te6edf3ref_energyTb4b4b4, Te6edf3corrTb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_disabled_by_couplingTb4b4b4: Tff7b72return Te6edf3frame
Tff7b72if Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_historyTb4b4b4) Tff7b72< Tff7b72selfTff7b72.Td2a8ffREQUIRED_COUPLING_HISTORYTb4b4b4: Tff7b72return Te6edf3frame
T8b949e# RNS.log(f"nA: {near_end_active}, coupling_db: {self._coupling_db}, eE: {predicted_echo_energy*1e7}, nE: {near_energy*1e7}")
Te6edf3should_gate Tff7b72= Te6edf3echo_correlated Tff7b72and Tff7b72not Te6edf3near_end_active
T8b949e# Gain smoothing
Te6edf3frame_duration_ms Tff7b72= Te6edf3N Tff7b72/ Te6edf3samplerate Tff7b72* T79c0ff1000.0
Te6edf3attack_coeff Tff7b72= T79c0ff1.0 Tff7b72- Te6edf3npTff7b72.Td2a8ffexpTb4b4b4(Tff7b72-Te6edf3frame_duration_ms Tff7b72/ Tff7b72selfTff7b72.Td2a8ffattack_msTb4b4b4)
Te6edf3release_coeff Tff7b72= T79c0ff1.0 Tff7b72- Te6edf3npTff7b72.Td2a8ffexpTb4b4b4(Tff7b72-Te6edf3frame_duration_ms Tff7b72/ Tff7b72selfTff7b72.Td2a8ffrelease_msTb4b4b4)
Tff7b72if Te6edf3near_end_activeTb4b4b4:
Te6edf3target_gain Tff7b72= T79c0ff1.0
Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72= T79c0ff0
Tff7b72elif Te6edf3should_gateTb4b4b4:
Te6edf3target_gain Tff7b72= T79c0ff0.0
Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72= Tffa657intTb4b4b4(Tff7b72selfTff7b72.Td2a8ffhangover_ms Tff7b72/ T79c0ff1000.0 Tff7b72* Te6edf3samplerateTb4b4b4)
Tff7b72elif Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3target_gain Tff7b72= T79c0ff0.0
Tff7b72selfTff7b72.Td2a8ff_hangover_samples Tff7b72-Tff7b72= Te6edf3N
Tff7b72elseTb4b4b4:
Te6edf3target_gain Tff7b72= T79c0ff1.0
Te6edf3coeff Tff7b72= Te6edf3attack_coeff Tff7b72if Te6edf3target_gain Tff7b72< Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72else Te6edf3release_coeff
Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72+Tff7b72= Tb4b4b4(Te6edf3target_gain Tff7b72- Tff7b72selfTff7b72.Td2a8ff_current_gainTb4b4b4) Tff7b72* Te6edf3coeff
Tff7b72if Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72< T79c0ff1e-6Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72= T79c0ff0.0
Tff7b72elif Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72> T79c0ff1.0Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72= T79c0ff1.0
Tff7b72if Tffa657lenTb4b4b4(Te6edf3original_shapeTb4b4b4) Tff7b72== T79c0ff1Tb4b4b4: Te6edf3output Tff7b72= Te6edf3mono_raw Tff7b72* Tff7b72selfTff7b72.Td2a8ff_current_gain
Tff7b72elseTb4b4b4: Te6edf3output Tff7b72= Te6edf3frame Tff7b72* Tff7b72selfTff7b72.Td2a8ff_current_gain
T8b949e# Comfort noise injection when gated
Tff7b72if Tff7b72selfTff7b72.Td2a8ffcng_enabled Tff7b72and Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72< T79c0ff0.05Tb4b4b4:
Te6edf3cng Tff7b72= Tff7b72selfTff7b72.Td2a8ff_get_cngTb4b4b4(Te6edf3outputTff7b72.Td2a8ffshapeTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3original_shapeTb4b4b4) Tff7b72== T79c0ff1Tb4b4b4:
Te6edf3output Tff7b72= Te6edf3output Tff7b72+ Te6edf3cng
Tff7b72elseTb4b4b4:
Te6edf3output Tff7b72= Te6edf3output Tff7b72+ Te6edf3cngTb4b4b4[Tb4b4b4:Tb4b4b4, Te6edf3npTff7b72.Td2a8ffnewaxisTb4b4b4]
Te6edf3output Tff7b72= Te6edf3npTff7b72.Td2a8ffclipTb4b4b4(Te6edf3outputTb4b4b4, Tff7b72-T79c0ff1.0Tb4b4b4, T79c0ff1.0Tb4b4b4)
Tff7b72if Tff7b72selfTff7b72.Td2a8ffdebug_metricsTb4b4b4: Te6edf3RNSTff7b72.Td2a8fflogTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffGT: Tffd700{Tff7b72selfTff7b72.Td2a8ff_current_gain Tff7b72< T79c0ff0.5Tffd700}Ta5d6ff, nA: Tffd700{Te6edf3near_end_activeTffd700}Ta5d6ff, EC: Tffd700{Te6edf3echo_correlatedTffd700}Ta5d6ff, SER: Tffd700{Tffa657roundTb4b4b4(Tff7b72selfTff7b72.Td2a8ffser_dbTb4b4b4,T79c0ff2Tb4b4b4)Tffd700}Ta5d6ff dB, coupling: Tffd700{Tffa657roundTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_coupling_dbTb4b4b4,T79c0ff2Tb4b4b4)Tffd700}Ta5d6ff dB, finish Tffd700{Te6edf3RNSTff7b72.Td2a8ffprettyshorttimeTb4b4b4(Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4)Tff7b72-Te6edf3stTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4, Te6edf3RNSTff7b72.Td2a8ffLOG_DEBUGTb4b4b4)
Tff7b72return Te6edf3output
Tf0883e@property
Tff7b72def Td2a8ffdelay_msTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_delay_ms
Tf0883e@property
Tff7b72def Td2a8ffdelay_samplesTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_delay_samples
Tf0883e@property
Tff7b72def Td2a8ffconfidenceTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_delay_confidence
Tf0883e@property
Tff7b72def Td2a8ffcoupling_dbTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_coupling_db
Tf0883e@property
Tff7b72def Td2a8ffgainTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4: Tff7b72return Tff7b72selfTff7b72.Td2a8ff_current_gain
T8b949e# class EchoCanceller(Filter):
T8b949e# # Delay estimator defaults
T8b949e# DEFAULT_MAX_DELAY_MS = 1000
T8b949e# DEFAULT_TRACK_WINDOW_MS = 150
T8b949e# DEFAULT_CORRELATION_FRAME_MS = 120
T8b949e# DEFAULT_CORRELATION_THRESHOLD = 0.070
T8b949e# DEFAULT_RMS_THRESHOLD = 0.002
T8b949e# DEFAULT_EMA_ALPHA = 0.2
T8b949e# DEFAULT_PREEMPH_ALPHA = 0.95
T8b949e# DEFAULT_ACC_FORGET = 0.92
T8b949e# # NLMS defaults
T8b949e# DEFAULT_FILTER_TAPS = 4096
T8b949e# DEFAULT_NLMS_MU = 0.8
T8b949e# DEFAULT_NLMS_EPS = 1e-12
T8b949e# DEFAULT_LEAKAGE = 0.9999
T8b949e# # Double-talk detection defaults
T8b949e# DEFAULT_DTD_THRESHOLD = 5.0 # hard freeze threshold, linear (~9.5 dB)
T8b949e# DEFAULT_DTD_HANGOVER_MS = 300 # keep frozen for N ms after trigger
T8b949e# DEFAULT_SOFT_DTD_THRESHOLD = 2.5 # soft freeze threshold, linear (~3.5 dB)
T8b949e# DEFAULT_SOFT_DTD_MU_SCALE = 0.3 # mu multiplier when in soft freeze
T8b949e# # Post-filter defaults
T8b949e# DEFAULT_PF_ENABLE = True
T8b949e# DEFAULT_PF_FFT_SIZE = 256
T8b949e# DEFAULT_PF_HOP_SIZE = 128
T8b949e# DEFAULT_PF_ALPHA = 12.0 # over-subtraction factor (1.0 = Wiener)
T8b949e# DEFAULT_PF_BETA = 0.0001 # spectral floor
T8b949e# DEFAULT_PF_SMOOTH = 0.5 # power smoothing coeff
T8b949e# DEFAULT_PF_ALPHA_SOFT = 0.8 # reduced aggression in soft freeze
T8b949e# DEFAULT_PF_ALPHA_HARD = 0.5 # minimal aggression in hard freeze
T8b949e# # Logging
T8b949e# LOG_INTERVAL_LOCKED = 0.25
T8b949e# LOG_INTERVAL_SEARCH = 0.5
T8b949e# PF_LOG_INTERVAL = 0.2 # post-filter debug output interval
T8b949e# def __init__(self, max_delay_ms=DEFAULT_MAX_DELAY_MS, track_window_ms=DEFAULT_TRACK_WINDOW_MS,
T8b949e# correlation_frame_ms=DEFAULT_CORRELATION_FRAME_MS, correlation_threshold=DEFAULT_CORRELATION_THRESHOLD,
T8b949e# rms_threshold=DEFAULT_RMS_THRESHOLD, ema_alpha=DEFAULT_EMA_ALPHA, preemph_alpha=DEFAULT_PREEMPH_ALPHA,
T8b949e# acc_forget=DEFAULT_ACC_FORGET, filter_taps=DEFAULT_FILTER_TAPS, nlms_mu=DEFAULT_NLMS_MU, nlms_eps=DEFAULT_NLMS_EPS,
T8b949e# leakage=DEFAULT_LEAKAGE, dtd_threshold=DEFAULT_DTD_THRESHOLD, dtd_hangover_ms=DEFAULT_DTD_HANGOVER_MS,
T8b949e# soft_dtd_threshold=DEFAULT_SOFT_DTD_THRESHOLD, soft_dtd_mu_scale=DEFAULT_SOFT_DTD_MU_SCALE,
T8b949e# pf_enable=DEFAULT_PF_ENABLE, pf_fft_size=DEFAULT_PF_FFT_SIZE, pf_hop_size=DEFAULT_PF_HOP_SIZE,
T8b949e# pf_alpha=DEFAULT_PF_ALPHA, pf_beta=DEFAULT_PF_BETA, pf_smooth=DEFAULT_PF_SMOOTH,
T8b949e# pf_alpha_soft=DEFAULT_PF_ALPHA_SOFT, pf_alpha_hard=DEFAULT_PF_ALPHA_HARD):
T8b949e# super().__init__()
T8b949e# # Delay estimator parameters
T8b949e# self.max_delay_ms = max_delay_ms
T8b949e# self.track_window_ms = track_window_ms
T8b949e# self.correlation_frame_ms = correlation_frame_ms
T8b949e# self.correlation_threshold = correlation_threshold
T8b949e# self.rms_threshold = rms_threshold
T8b949e# self.ema_alpha = ema_alpha
T8b949e# self.preemph_alpha = preemph_alpha
T8b949e# self.acc_forget = acc_forget
T8b949e# # NLMS parameters
T8b949e# self.filter_taps = filter_taps
T8b949e# self.nlms_mu = nlms_mu
T8b949e# self.nlms_eps = nlms_eps
T8b949e# self.leakage = leakage
T8b949e# self.dtd_threshold = dtd_threshold
T8b949e# self.dtd_hangover_ms = dtd_hangover_ms
T8b949e# self.soft_dtd_threshold = soft_dtd_threshold
T8b949e# self.soft_dtd_mu_scale = soft_dtd_mu_scale
T8b949e# # Post-filter parameters
T8b949e# self.pf_enable = pf_enable
T8b949e# self.pf_fft_size = pf_fft_size
T8b949e# self.pf_hop_size = pf_hop_size
T8b949e# self.pf_alpha = pf_alpha
T8b949e# self.pf_beta = pf_beta
T8b949e# self.pf_smooth = pf_smooth
T8b949e# self.pf_alpha_soft = pf_alpha_soft
T8b949e# self.pf_alpha_hard = pf_alpha_hard
T8b949e# # Threading / state
T8b949e# self._lock = threading.Lock()
T8b949e# self._samplerate = None
T8b949e# # Reference ring buffer (pre-emphasised)
T8b949e# self._buffer_size = None
T8b949e# self._ref_buffer = None
T8b949e# self._ref_write_pos = 0
T8b949e# self._ref_valid = 0
T8b949e# self._max_delay_samples = None
T8b949e# self._track_window_samples = None
T8b949e# self._correlation_samples = None
T8b949e# # Pre-emphasis / de-emphasis states
T8b949e# self._ref_preemph_state = np.float32(0.0)
T8b949e# self._mic_preemph_state = np.float32(0.0)
T8b949e# self._deemph_state = np.float32(0.0)
T8b949e# # Mic history for delay estimation
T8b949e# self._mic_hist = None
T8b949e# self._mic_hist_write = 0
T8b949e# self._mic_hist_valid = 0
T8b949e# # Delay accumulator
T8b949e# self._corr_acc = None
T8b949e# # NLMS coefficients
T8b949e# self._w = None
T8b949e# # Delay estimate
T8b949e# self._delay_samples = None
T8b949e# self._delay_ms = None
T8b949e# self._delay_confidence = 0.0
T8b949e# # Logging / counters
T8b949e# self._last_log_time = 0
T8b949e# self._frame_count = 0
T8b949e# # Double-talk state
T8b949e# self._dtd_hangover_counter = 0
T8b949e# self._dtd_was_frozen = False
T8b949e# # Post-filter state
T8b949e# self._pf_inbuf = None
T8b949e# self._pf_ecbuf = None
T8b949e# self._pf_outbuf = None
T8b949e# self._pf_synbuf = None
T8b949e# self._pf_window = None
T8b949e# self._pf_echo_power = None
T8b949e# self._pf_res_power = None
T8b949e# # Post-filter debug accumulator
T8b949e# self._pf_last_debug_time = 0
T8b949e# self._pf_debug_frames = 0
T8b949e# self._pf_debug_acc = None
T8b949e# # Helpers
T8b949e# @staticmethod
T8b949e# def _to_mono(frame):
T8b949e# if frame.ndim == 1: return frame.astype(np.float32, copy=False)
T8b949e# elif frame.ndim == 2:
T8b949e# if frame.shape[1] == 1: return frame[:, 0].astype(np.float32, copy=False)
T8b949e# return frame.mean(axis=1).astype(np.float32)
T8b949e# else: return frame.astype(np.float32, copy=False).ravel()
T8b949e# def _preemph(self, x, state):
T8b949e# # First-order pre-emphasis filter
T8b949e# y = np.empty_like(x)
T8b949e# a = np.float32(self.preemph_alpha)
T8b949e# y[0] = x[0] - a * state
T8b949e# y[1:] = x[1:] - a * x[:-1]
T8b949e# return y, x[-1]
T8b949e# def _deemph(self, x, state):
T8b949e# # Inverse of pre-emphasis
T8b949e# y = np.empty_like(x)
T8b949e# a = np.float32(self.preemph_alpha)
T8b949e# y[0] = x[0] + a * state
T8b949e# for i in range(1, len(x)):
T8b949e# y[i] = x[i] + a * y[i - 1]
T8b949e# return y, y[-1]
T8b949e# def _ensure_buffer(self, samplerate):
T8b949e# if self._samplerate != samplerate or self._ref_buffer is None:
T8b949e# self._samplerate = samplerate
T8b949e# self._max_delay_samples = int(self.max_delay_ms / 1000.0 * samplerate)
T8b949e# self._track_window_samples = int(self.track_window_ms / 1000.0 * samplerate)
T8b949e# self._correlation_samples = int(self.correlation_frame_ms / 1000.0 * samplerate)
T8b949e# # Reference buffer: max delay + margin
T8b949e# self._buffer_size = self._max_delay_samples + 16384
T8b949e# self._ref_buffer = np.zeros(self._buffer_size, dtype=np.float32)
T8b949e# self._ref_write_pos = 0
T8b949e# self._ref_valid = 0
T8b949e# self._corr_acc = np.zeros(self._max_delay_samples + 1, dtype=np.float64)
T8b949e# self._mic_hist = np.zeros(self._correlation_samples, dtype=np.float32)
T8b949e# self._mic_hist_write = 0
T8b949e# self._mic_hist_valid = 0
T8b949e# self._w = np.zeros(self.filter_taps, dtype=np.float32)
T8b949e# # Post-filter state
T8b949e# if self.pf_enable:
T8b949e# self._pf_inbuf = []
T8b949e# self._pf_ecbuf = []
T8b949e# self._pf_outbuf = []
T8b949e# self._pf_synbuf = np.zeros(self.pf_fft_size, dtype=np.float32)
T8b949e# self._pf_window = np.sqrt(np.hanning(self.pf_fft_size)).astype(np.float32)
T8b949e# half_bins = self.pf_fft_size // 2 + 1
T8b949e# self._pf_echo_power = np.zeros(half_bins, dtype=np.float64)
T8b949e# self._pf_res_power = np.zeros(half_bins, dtype=np.float64)
T8b949e# # Debug accumulator
T8b949e# self._pf_last_debug_time = 0
T8b949e# self._pf_debug_frames = 0
T8b949e# self._pf_debug_acc = { 'nlms_pre': 0.0, 'nlms_out': 0.0, 'total_out': 0.0,
T8b949e# 'gain_mean': 0.0, 'gain_min': 0.0, 'floor_pct': 0.0,
T8b949e# 'ratio_mean_db': 0.0, 'ratio_max_db': 0.0,
T8b949e# 'power_echo_db': 0.0, 'power_res_db': 0.0 }
T8b949e# pf_info = f", post-filter={self.pf_fft_size}/{self.pf_hop_size}" if self.pf_enable else ", post-filter=off"
T8b949e# RNS.log(f"EchoCanceller initialised: max_delay={self.max_delay_ms}ms, "
T8b949e# f"corr_window={self.correlation_frame_ms}ms, taps={self.filter_taps}, "
T8b949e# f"mu={self.nlms_mu}, threshold={self.correlation_threshold}, "
T8b949e# f"DTD_hard={self.dtd_threshold}dB({20*np.log10(self.dtd_threshold):.1f}), "
T8b949e# f"DTD_soft={self.soft_dtd_threshold}dB({20*np.log10(self.soft_dtd_threshold):.1f}), "
T8b949e# f"hangover={self.dtd_hangover_ms}ms{pf_info}, @ {samplerate}Hz",
T8b949e# RNS.LOG_DEBUG)
T8b949e# def _append_reference(self, mono):
T8b949e# N = len(mono)
T8b949e# if N > self._buffer_size:
T8b949e# mono = mono[-self._buffer_size:]
T8b949e# N = self._buffer_size
T8b949e# end = self._ref_write_pos + N
T8b949e# if end <= self._buffer_size: self._ref_buffer[self._ref_write_pos:end] = mono
T8b949e# else:
T8b949e# part1 = self._buffer_size - self._ref_write_pos
T8b949e# self._ref_buffer[self._ref_write_pos:] = mono[:part1]
T8b949e# self._ref_buffer[:end - self._buffer_size] = mono[part1:]
T8b949e# self._ref_write_pos = end % self._buffer_size
T8b949e# self._ref_valid = min(self._ref_valid + N, self._buffer_size)
T8b949e# def _append_mic_history(self, mono):
T8b949e# N = len(mono)
T8b949e# if N >= self._correlation_samples:
T8b949e# self._mic_hist[:] = mono[-self._correlation_samples:]
T8b949e# self._mic_hist_write = 0
T8b949e# self._mic_hist_valid = self._correlation_samples
T8b949e# return
T8b949e# end = self._mic_hist_write + N
T8b949e# if end <= self._correlation_samples: self._mic_hist[self._mic_hist_write:end] = mono
T8b949e# else:
T8b949e# part1 = self._correlation_samples - self._mic_hist_write
T8b949e# self._mic_hist[self._mic_hist_write:] = mono[:part1]
T8b949e# self._mic_hist[:end - self._correlation_samples] = mono[part1:]
T8b949e# self._mic_hist_write = end % self._correlation_samples
T8b949e# self._mic_hist_valid = min(self._mic_hist_valid + N, self._correlation_samples)
T8b949e# def _get_reference_window(self, length):
T8b949e# length = min(length, self._ref_valid)
T8b949e# if length <= 0: return np.array([], dtype=np.float32)
T8b949e# start = (self._ref_write_pos - length) % self._buffer_size
T8b949e# end = self._ref_write_pos
T8b949e# if start < end: return self._ref_buffer[start:end].copy()
T8b949e# else: return np.concatenate( (self._ref_buffer[start:].copy(), self._ref_buffer[:end].copy()) )
T8b949e# def _get_mic_history(self):
T8b949e# length = min(self._mic_hist_valid, self._correlation_samples)
T8b949e# if length <= 0: return np.array([], dtype=np.float32)
T8b949e# start = (self._mic_hist_write - length) % self._correlation_samples
T8b949e# end = self._mic_hist_write
T8b949e# if start < end: return self._mic_hist[start:end].copy()
T8b949e# else: return np.concatenate( (self._mic_hist[start:].copy(), self._mic_hist[:end].copy()) )
T8b949e# # Post-filter
T8b949e# def _pf_process(self, residual, echo_estimate, alpha):
T8b949e# # STFT overlap-add power-subtraction post-filter
T8b949e# #
T8b949e# # Operates in the time domain after de-emphasis so that
T8b949e# # suppression is not undone by the de-emphasis IIR.
T8b949e# #
T8b949e# # Uses the gain rule::
T8b949e# #
T8b949e# # G = max( 1 - alpha * P_echo / P_res , beta )
T8b949e# #
T8b949e# # where *P_res* is the smoothed power of the residual and
T8b949e# # *P_echo* the smoothed power of the echo estimate. Returns
T8b949e# # the filtered time-domain signal and a dict of diagnostic stats.
T8b949e# N = len(residual)
T8b949e# self._pf_inbuf.extend(residual)
T8b949e# self._pf_ecbuf.extend(echo_estimate)
T8b949e# fft_size = self.pf_fft_size
T8b949e# hop = self.pf_hop_size
T8b949e# window = self._pf_window
T8b949e# synbuf = self._pf_synbuf
T8b949e# outbuf = self._pf_outbuf
T8b949e# block_stats = []
T8b949e# while len(self._pf_inbuf) >= fft_size:
T8b949e# x = np.array(self._pf_inbuf[:fft_size], dtype=np.float32) * window
T8b949e# e = np.array(self._pf_ecbuf[:fft_size], dtype=np.float32) * window
T8b949e# X = np.fft.rfft(x)
T8b949e# E = np.fft.rfft(e)
T8b949e# absX2 = np.abs(X) ** 2
T8b949e# absE2 = np.abs(E) ** 2
T8b949e# self._pf_res_power = self.pf_smooth * self._pf_res_power + (1.0 - self.pf_smooth) * absX2
T8b949e# self._pf_echo_power = self.pf_smooth * self._pf_echo_power + (1.0 - self.pf_smooth) * absE2
T8b949e# # Classic power-subtraction ratio
T8b949e# with np.errstate(divide='ignore', invalid='ignore'):
T8b949e# ratio = self._pf_echo_power / (self._pf_res_power + 1e-12)
T8b949e# ratio = np.clip(ratio, 0.0, 1e6)
T8b949e# gain = 1.0 - alpha * ratio
T8b949e# np.clip(gain, self.pf_beta, 1.0, out=gain)
T8b949e# # Collect stats for this block
T8b949e# valid_bins = len(gain)
T8b949e# floor_count = int(np.sum(gain <= self.pf_beta + 1e-9))
T8b949e# block_stats.append( {'gain_mean': float(np.mean(gain)),
T8b949e# 'gain_min': float(np.min(gain)),
T8b949e# 'floor_pct': 100.0 * floor_count / valid_bins,
T8b949e# 'ratio_mean_db': float(10.0 * np.log10(np.mean(ratio) + 1e-12)),
T8b949e# 'ratio_max_db': float(10.0 * np.log10(np.max(ratio) + 1e-12)),
T8b949e# 'power_echo_db': float(10.0 * np.log10(np.mean(self._pf_echo_power) + 1e-12)),
T8b949e# 'power_res_db': float(10.0 * np.log10(np.mean(self._pf_res_power) + 1e-12))} )
T8b949e# Y = X * gain
T8b949e# y = np.fft.irfft(Y, n=fft_size) * window
T8b949e# synbuf += y
T8b949e# outbuf.extend(synbuf[:hop].tolist())
T8b949e# synbuf[:-hop] = synbuf[hop:]
T8b949e# synbuf[-hop:] = 0.0
T8b949e# del self._pf_inbuf[:hop]
T8b949e# del self._pf_ecbuf[:hop]
T8b949e# if len(outbuf) >= N:
T8b949e# result = np.array(outbuf[:N], dtype=np.float32)
T8b949e# del outbuf[:N]
T8b949e# return result, block_stats
T8b949e# else:
T8b949e# available = len(outbuf)
T8b949e# result = np.empty(N, dtype=np.float32)
T8b949e# if available > 0:
T8b949e# result[:available] = np.array(outbuf[:available], dtype=np.float32)
T8b949e# del outbuf[:available]
T8b949e# result[available:] = residual[available:]
T8b949e# return result, block_stats
T8b949e# def _pf_flush_debug(self, now, force=False):
T8b949e# if self._pf_debug_frames == 0: return
T8b949e# if not force and now - self._pf_last_debug_time < self.PF_LOG_INTERVAL: return
T8b949e# n = self._pf_debug_frames
T8b949e# acc = self._pf_debug_acc
T8b949e# RNS.log(f"EchoCanceller PF: "
T8b949e# f"nlms_pre={acc['nlms_pre']/n:.1f}dB "
T8b949e# f"nlms_out={acc['nlms_out']/n:.1f}dB "
T8b949e# f"total_out={acc['total_out']/n:.1f}dB "
T8b949e# f"gain_mean={acc['gain_mean']/n:.3f} "
T8b949e# f"gain_min={acc['gain_min']/n:.3f} "
T8b949e# f"floor_pct={acc['floor_pct']/n:.1f}% "
T8b949e# f"ratio_mean={acc['ratio_mean_db']/n:.1f}dB "
T8b949e# f"ratio_max={acc['ratio_max_db']/n:.1f}dB "
T8b949e# f"Pecho={acc['power_echo_db']/n:.1f}dB "
T8b949e# f"Pres={acc['power_res_db']/n:.1f}dB "
T8b949e# f"frames={n}",
T8b949e# RNS.LOG_DEBUG)
T8b949e# self._pf_last_debug_time = now
T8b949e# self._pf_debug_frames = 0
T8b949e# for k in acc: acc[k] = 0.0
T8b949e# # Public interface
T8b949e# def handle_reference(self, frame, samplerate):
T8b949e# mono = self._to_mono(frame)
T8b949e# mono, self._ref_preemph_state = self._preemph(mono, self._ref_preemph_state)
T8b949e# with self._lock:
T8b949e# self._ensure_buffer(samplerate)
T8b949e# self._append_reference(mono)
T8b949e# def handle_frame(self, frame, samplerate):
T8b949e# original_shape = frame.shape
T8b949e# mono = self._to_mono(frame)
T8b949e# N = len(mono)
T8b949e# if N == 0: return frame
T8b949e# mic_rms = np.sqrt(np.mean(mono ** 2))
T8b949e# if mic_rms < self.rms_threshold: return frame
T8b949e# # Pre-emphasise mic for both delay estimation and NLMS
T8b949e# mono_pre, self._mic_preemph_state = self._preemph(mono, self._mic_preemph_state)
T8b949e# # 1. Delay estimation
T8b949e# seg = None
T8b949e# with self._lock:
T8b949e# if self._ref_valid < N + 100: return frame
T8b949e# if self._samplerate != samplerate:
T8b949e# RNS.log(f"EchoCanceller samplerate mismatch (ref={self._samplerate}, mic={samplerate}), skipping", RNS.LOG_WARNING)
T8b949e# return frame
T8b949e# # Accumulate history
T8b949e# self._append_mic_history(mono_pre)
T8b949e# if self._mic_hist_valid < self._correlation_samples // 2: return frame
T8b949e# mic_window = self._get_mic_history()
T8b949e# search_length = min(self._ref_valid, self._max_delay_samples + len(mic_window))
T8b949e# if search_length <= len(mic_window): return frame
T8b949e# ref_window = self._get_reference_window(search_length)
T8b949e# # FFT-based cross-correlation
T8b949e# M = len(ref_window)
T8b949e# Nc = len(mic_window)
T8b949e# fft_size = 1 << (M + Nc - 1).bit_length()
T8b949e# C = np.fft.irfft( np.fft.rfft(ref_window, n=fft_size) *
T8b949e# np.conj(np.fft.rfft(mic_window, n=fft_size)),
T8b949e# n=fft_size )
T8b949e# c = C[:M - Nc + 1]
T8b949e# mic_norm = np.linalg.norm(mic_window)
T8b949e# if mic_norm == 0: return frame
T8b949e# ref_sq = ref_window ** 2
T8b949e# ref_cumsum = np.concatenate(([0.0], np.cumsum(ref_sq, dtype=np.float64)))
T8b949e# window_norms = np.sqrt(ref_cumsum[Nc:] - ref_cumsum[:-Nc])
T8b949e# with np.errstate(divide='ignore', invalid='ignore'): corr = c / (mic_norm * window_norms)
T8b949e# corr[window_norms == 0] = 0
T8b949e# abs_corr = np.abs(corr)
T8b949e# # Accumulate
T8b949e# self._corr_acc *= self.acc_forget
T8b949e# self._corr_acc[:len(abs_corr)] += abs_corr[::-1]
T8b949e# acc_norm = self._corr_acc * (1.0 - self.acc_forget)
T8b949e# # Statistics for logging
T8b949e# abs_mean = float(np.mean(abs_corr))
T8b949e# abs_std = float(np.std(abs_corr))
T8b949e# # Search for peak
T8b949e# if self._delay_samples is not None:
T8b949e# d_est = int(round(self._delay_samples))
T8b949e# d_min = max(0, d_est - self._track_window_samples)
T8b949e# d_max = min(len(acc_norm) - 1, d_est + self._track_window_samples)
T8b949e# track_acc = acc_norm[d_min:d_max + 1]
T8b949e# best_local_idx = np.argmax(track_acc)
T8b949e# best_delay = d_min + best_local_idx
T8b949e# best_val = float(track_acc[best_local_idx])
T8b949e# if best_val < self.correlation_threshold:
T8b949e# best_delay = int(np.argmax(acc_norm))
T8b949e# best_val = float(acc_norm[best_delay])
T8b949e# else:
T8b949e# best_delay = int(np.argmax(acc_norm))
T8b949e# best_val = float(acc_norm[best_delay])
T8b949e# prominence = (best_val - abs_mean) / (abs_std + 1e-12)
T8b949e# raw_delay_ms = best_delay / self._samplerate * 1000.0
T8b949e# self._frame_count += 1
T8b949e# now = time.time()
T8b949e# if best_val >= self.correlation_threshold:
T8b949e# if self._delay_samples is None:
T8b949e# self._delay_samples = float(best_delay)
T8b949e# self._delay_ms = raw_delay_ms
T8b949e# self._delay_confidence = best_val
T8b949e# else:
T8b949e# self._delay_samples = ( self.ema_alpha * best_delay + (1.0 - self.ema_alpha) * self._delay_samples )
T8b949e# self._delay_ms = self._delay_samples / self._samplerate * 1000.0
T8b949e# self._delay_confidence = ( self.ema_alpha * best_val + (1.0 - self.ema_alpha) * self._delay_confidence )
T8b949e# # if (now - self._last_log_time > self.LOG_INTERVAL_LOCKED or abs(raw_delay_ms - self._delay_ms) > 5):
T8b949e# # RNS.log(f"EchoCanceller delay estimate: {self._delay_ms:.1f} ms "
T8b949e# # f"(confidence={self._delay_confidence:.3f}, "
T8b949e# # f"raw={raw_delay_ms:.1f} ms, val={best_val:.4f}, "
T8b949e# # f"prom={prominence:.1f})",
T8b949e# # RNS.LOG_DEBUG)
T8b949e# # self._last_log_time = now
T8b949e# # else:
T8b949e# # if (self._delay_samples is None and (self._frame_count % 3 == 0 or now - self._last_log_time > self.LOG_INTERVAL_SEARCH)):
T8b949e# # RNS.log(f"EchoCanceller searching: max={best_val:.4f}, "
T8b949e# # f"mean={abs_mean:.4f}, std={abs_std:.4f}, "
T8b949e# # f"prom={prominence:.1f}, peak_delay={raw_delay_ms:.1f}ms, "
T8b949e# # f"hist_valid={self._mic_hist_valid}",
T8b949e# # RNS.LOG_DEBUG)
T8b949e# # self._last_log_time = now
T8b949e# # Prepare aligned reference segment for NLMS
T8b949e# if self._delay_samples is not None:
T8b949e# int_delay = int(round(self._delay_samples))
T8b949e# needed = int_delay + N + self.filter_taps - 1
T8b949e# if self._ref_valid >= needed:
T8b949e# rw = self._get_reference_window(needed)
T8b949e# seg = rw[:N + self.filter_taps - 1]
T8b949e# # 2. NLMS adaptive filter
T8b949e# if seg is None or len(seg) < N + self.filter_taps - 1: return frame
T8b949e# L = self.filter_taps
T8b949e# w = self._w
T8b949e# mu = self.nlms_mu
T8b949e# eps = self.nlms_eps
T8b949e# leakage = self.leakage
T8b949e# clean_pre = np.empty(N, dtype=np.float32)
T8b949e# echo_pre = np.empty(N, dtype=np.float32)
T8b949e# # Frame-level double-talk detection
T8b949e# ref_aligned = seg[L - 1:L - 1 + N]
T8b949e# ref_peak = np.max(np.abs(ref_aligned))
T8b949e# mic_peak = np.max(np.abs(mono_pre))
T8b949e# ratio = mic_peak / (ref_peak + 1e-12)
T8b949e# hard_freeze = ratio > self.dtd_threshold
T8b949e# if hard_freeze:
T8b949e# self._dtd_hangover_counter = int(self.dtd_hangover_ms / 1000.0 * self._samplerate)
T8b949e# freeze = True
T8b949e# elif self._dtd_hangover_counter > 0:
T8b949e# freeze = True
T8b949e# self._dtd_hangover_counter -= N
T8b949e# else:
T8b949e# freeze = False
T8b949e# soft_freeze = (not freeze) and (ratio > self.soft_dtd_threshold)
T8b949e# effective_mu = mu * self.soft_dtd_mu_scale if soft_freeze else mu
T8b949e# if freeze: pf_alpha = self.pf_alpha_hard
T8b949e# elif soft_freeze: pf_alpha = self.pf_alpha_soft
T8b949e# else: pf_alpha = self.pf_alpha
T8b949e# if freeze != self._dtd_was_frozen:
T8b949e# state = "frozen" if freeze else "active"
T8b949e# RNS.log(f"EchoCanceller DTD {state} (ratio={ratio:.2f}, ref_peak={ref_peak:.4f}, mic_peak={mic_peak:.4f})", RNS.LOG_DEBUG)
T8b949e# self._dtd_was_frozen = freeze
T8b949e# for i in range(N):
T8b949e# x = seg[i:i + L][::-1]
T8b949e# y_hat = np.dot(w, x)
T8b949e# e = mono_pre[i] - y_hat
T8b949e# clean_pre[i] = e
T8b949e# echo_pre[i] = y_hat
T8b949e# if not freeze:
T8b949e# pw = np.dot(x, x)
T8b949e# w *= leakage
T8b949e# w += effective_mu * e * x / (pw + eps)
T8b949e# # 3. De-emphasis
T8b949e# clean_raw_nlms, self._deemph_state = self._deemph(clean_pre, self._deemph_state)
T8b949e# if self.pf_enable and self._pf_window is not None:
T8b949e# echo_time = mono - clean_raw_nlms
T8b949e# filtered_raw, block_stats = self._pf_process(clean_raw_nlms, echo_time, pf_alpha)
T8b949e# else:
T8b949e# filtered_raw = clean_raw_nlms
T8b949e# block_stats = []
T8b949e# # 4. Frame-level ERLE and spectral diagnostics
T8b949e# power_mic = np.mean(mono ** 2)
T8b949e# power_nlms = np.mean(clean_raw_nlms ** 2)
T8b949e# power_pf = np.mean(filtered_raw ** 2)
T8b949e# power_mic_pre = np.mean(mono_pre ** 2)
T8b949e# power_nlms_pre = np.mean(clean_pre ** 2)
T8b949e# if power_nlms_pre > 1e-18: erle_nlms_pre = 10.0 * np.log10(power_mic_pre / power_nlms_pre)
T8b949e# else: erle_nlms_pre = 99.0
T8b949e# if power_nlms > 1e-18: erle_nlms_out = 10.0 * np.log10(power_mic / power_nlms)
T8b949e# else: erle_nlms_out = 99.0
T8b949e# if power_pf > 1e-18: erle_total_out = 10.0 * np.log10(power_mic / power_pf)
T8b949e# else: erle_total_out = 99.0
T8b949e# if block_stats:
T8b949e# avg = { 'gain_mean': sum(s['gain_mean'] for s in block_stats) / len(block_stats),
T8b949e# 'gain_min': sum(s['gain_min'] for s in block_stats) / len(block_stats),
T8b949e# 'floor_pct': sum(s['floor_pct'] for s in block_stats) / len(block_stats),
T8b949e# 'ratio_mean_db': sum(s['ratio_mean_db'] for s in block_stats) / len(block_stats),
T8b949e# 'ratio_max_db': sum(s['ratio_max_db'] for s in block_stats) / len(block_stats),
T8b949e# 'power_echo_db': sum(s['power_echo_db'] for s in block_stats) / len(block_stats),
T8b949e# 'power_res_db': sum(s['power_res_db'] for s in block_stats) / len(block_stats) }
T8b949e# else:
T8b949e# avg = { 'gain_mean': 1.0, 'gain_min': 1.0, 'floor_pct': 0.0, 'ratio_mean_db': -99.0,
T8b949e# 'ratio_max_db': -99.0, 'power_echo_db': -99.0, 'power_res_db': -99.0 }
T8b949e# acc = self._pf_debug_acc
T8b949e# acc['nlms_pre'] += erle_nlms_pre
T8b949e# acc['nlms_out'] += erle_nlms_out
T8b949e# acc['total_out'] += erle_total_out
T8b949e# acc['gain_mean'] += avg['gain_mean']
T8b949e# acc['gain_min'] += avg['gain_min']
T8b949e# acc['floor_pct'] += avg['floor_pct']
T8b949e# acc['ratio_mean_db'] += avg['ratio_mean_db']
T8b949e# acc['ratio_max_db'] += avg['ratio_max_db']
T8b949e# acc['power_echo_db'] += avg['power_echo_db']
T8b949e# acc['power_res_db'] += avg['power_res_db']
T8b949e# self._pf_debug_frames += 1
T8b949e# now = time.time()
T8b949e# self._pf_flush_debug(now)
T8b949e# # Compute echo estimate and subtract from original channels
T8b949e# echo_mono = mono - filtered_raw
T8b949e# if len(original_shape) == 1: output = filtered_raw
T8b949e# else: output = frame - echo_mono[:, np.newaxis]
T8b949e# return output
T8b949e# @property
T8b949e# def delay_ms(self): return self._delay_ms
T8b949e# @property
T8b949e# def delay_samples(self): return self._delay_samples
T8b949e# @property
T8b949e# def confidence(self): return self._delay_confidence
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────